https://leetcode-cn.com/problems/coin-change/submissions/

动态规划

  • dp[ i ][ j ]

    • arr[ 0…i ]所有钱自由使用,能拼出 j 元的最小硬币个数
  • 初始化

image.png

  • 普遍位置怎么填?dp[ i ][ j ]
    • 0) 0张[ i ]钱, —> dp[ i - 1 ][ j ]
    • 1) 1张[ i ]钱, —> dp[ i - 1 ][ j - coins[ i ] ] + 1
    • 2) 2张[ i ]钱, —> dp[ i - 1 ][ j - coins[ i ] * 2 ] + 2
    • …) …..
    • k) k张[ i ]钱, —> dp[ i - 1 ][ j - coins[ i ] * k ] + k
  • 可以看出dp[i][j]有枚举行为——->斜率优化(观察自己临近的位置,看能不能把枚举行为省掉)

image.png
image.png
image.png

  1. public int coinChange(int[] coins, int amount) {
  2. if (coins == null || coins.length == 0 || amount == 0) {
  3. return -1;
  4. }
  5. int N = coins.length;
  6. int[][] dp = new int[N][amount + 1];
  7. // dp[i][0] = 0 0列不需要填
  8. // dp[0][1...] = arr[0]的整数倍,有张数,倍数,其他的格子-1(表示无方案)
  9. for (int j = 1; j <= amount; j++) {
  10. if (j % coins[0] != 0) {
  11. dp[0][j] = -1;
  12. } else {
  13. dp[0][j] = j / coins[0];
  14. }
  15. }
  16. for (int i = 1; i < N; i++) {
  17. for (int j = 1; j <= amount; j++) {
  18. //dp[i][j] = Math.min(dp[i - 1][j], dp[i][j - coins[i]]);
  19. dp[i][j] = Integer.MAX_VALUE;
  20. if (dp[i - 1][j] != -1) {
  21. dp[i][j] = dp[i - 1][j];
  22. }
  23. if (j - coins[i] >= 0 && dp[i][j - coins[i]] != -1) {
  24. dp[i][j] = Math.min(dp[i][j], dp[i][j - coins[i]] + 1);
  25. }
  26. if (dp[i][j] == Integer.MAX_VALUE) {
  27. dp[i][j] = -1;
  28. }
  29. }
  30. }
  31. return dp[N - 1][amount];
  32. }