The problem is typical Knapsack problem.

https://en.wikipedia.org/wiki/Knapsack_problem

The idea is, each coin can be used infinitely. So the inner loop of dp is ascending. If one coin can only be used once, the inner loop should be descending.

```
public class Solution {
public int coinChange(int[] coins, int amount) {
int[] dp = new int[amount + 1];
Arrays.fill(dp, Integer.MAX_VALUE);
dp[0] = 0;
for (int coin : coins) {
for (int j = coin; j <= amount; j++) {
if (dp[j - coin] != Integer.MAX_VALUE) {
dp[j] = Math.min(dp[j], dp[j - coin] + 1);
}
}
}
return dp[amount] == Integer.MAX_VALUE ? -1 : dp[amount];
}
}
```