其实自己也看不太懂....蛋疼
aim = 11
coins = {1, 2, 5}
如:11
针对金额1 可以拆分为 1 + 10
针对金额2 可以拆分为 2 + 9
针对金额5 可以拆分为 5 + 6

但此时的 1 2 5 都代表当前金额coins[i],即属于1次拆分
如:1 + fx(10) 代表 除去当前把金额1拆分了一次之后,后续的10 还需要几次拆分
如:1 + fx(9) 代表 除去当前把金额2拆分了一次之后,后续的9 还需要几次拆分
如:1 + fx(6) 代表 除去当前把金额5拆分了一次之后,后续的6 还需要几次拆分

fx(11) = 1 + fx(10) 1 + fx(9) 1 + fx(6)

fx(10) = 1 + fx(9) 1 + fx(8) 1 + fx(5)

fx(9) = 1 + fx(8) 1 + fx(7) 1 + fx(4)

fx(8) = 1 + fx(7) 1 + fx(6) 1 + fx(3)

fx(7) = 1 + fx(6) 1 + fx(5) 1 + fx(2)

fx(6) = 1 + fx(5) 1 + fx(4) 1 + fx(1)

fx(5) = 1 + fx(4) 1 + fx(3) 1 + fx(0)

fx(4) = 1 + fx(3) 1 + fx(2) x(无法拆分)

fx(3) = 1 + fx(2) 1 + fx(1) x(无法拆分)

fx(2) = 1 + fx(1) 1 + fx(0) x(无法拆分)

fx(1) = 1 + fx(0) x(无法拆分) x(无法拆分)

fx(0) = x(无法拆分) x(无法拆分) x(无法拆分)
fx(0) = 0 0 0

所以fx(0) 默认都填充为0

进行填充 并且每行取最小再向上推算

fx(11) = Min(1 + fx(10) 1 + fx(9) 1 + fx(6))

fx(10) = Min(1 + fx(9) 1 + fx(8) 1 + fx(5))

fx(9) = Min(1 + fx(8) 1 + fx(7) 1 + fx(4))

fx(8) = Min(1 + fx(7) 1 + fx(6) 1 + fx(3))

fx(7) = Min(1 + fx(6) 1 + fx(5) 1 + fx(2))

fx(6) = Min(1 + fx(5) 1 + fx(4) 1 + fx(1))

fx(5) = Min(1 + fx(4) 1 + fx(3) 1 + fx(0))

fx(4) = Min(1 + fx(3) 1 + fx(2) x )

fx(3) = Min(1 + fx(2) 1 + fx(1) x )

fx(2) = Min(1 + fx(1) 1 + fx(0) x )

fx(1) = Min(1 + fx(0) x x )

fx(0) = Min(0 0 0 )

取小后结果:

fx(11) = 3

fx(10) = 2

fx(9) = 3

fx(8) = 3

fx(7) = 2

fx(6) = 2

fx(5) = 1

fx(4) = 2

fx(3) = 2

fx(2) = 1

fx(1) = 1

fx(0) = 0

public static void main(String[] args) {
int[] arr = {1, 2, 5};
int aim = 11;

    int max = aim + 1;
    //多出的1列 是索引为0的初始列 因为要让dp[0]=0
    int[] dp = new int[aim + 1];
    Arrays.fill(dp, max);
    dp[0] = 0;
    for (int i = 0; i < arr.length; i++) {
        for (int j = arr[i]; j <= aim; j++) {
            if (arr[i] <= j) {
                dp[j] = Math.min(dp[j], dp[j - arr[i]] + 1);
                System.out.println(Arrays.toString(dp));
            }
        }
    }

}
打印结果:
[0, 1, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12]
[0, 1, 2, 12, 12, 12, 12, 12, 12, 12, 12, 12]
[0, 1, 2, 3, 12, 12, 12, 12, 12, 12, 12, 12]
[0, 1, 2, 3, 4, 12, 12, 12, 12, 12, 12, 12]
[0, 1, 2, 3, 4, 5, 12, 12, 12, 12, 12, 12]
[0, 1, 2, 3, 4, 5, 6, 12, 12, 12, 12, 12]
[0, 1, 2, 3, 4, 5, 6, 7, 12, 12, 12, 12]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 12, 12, 12]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 12, 12]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
[0, 1, 1, 3, 4, 5, 6, 7, 8, 9, 10, 11]
[0, 1, 1, 2, 4, 5, 6, 7, 8, 9, 10, 11]
[0, 1, 1, 2, 2, 5, 6, 7, 8, 9, 10, 11]
[0, 1, 1, 2, 2, 3, 6, 7, 8, 9, 10, 11]
[0, 1, 1, 2, 2, 3, 3, 7, 8, 9, 10, 11]
[0, 1, 1, 2, 2, 3, 3, 4, 8, 9, 10, 11]
[0, 1, 1, 2, 2, 3, 3, 4, 4, 9, 10, 11]
[0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 10, 11]
[0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 11]
[0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6]
[0, 1, 1, 2, 2, 1, 3, 4, 4, 5, 5, 6]
[0, 1, 1, 2, 2, 1, 2, 4, 4, 5, 5, 6]
[0, 1, 1, 2, 2, 1, 2, 2, 4, 5, 5, 6]
[0, 1, 1, 2, 2, 1, 2, 2, 3, 5, 5, 6]
[0, 1, 1, 2, 2, 1, 2, 2, 3, 3, 5, 6]
[0, 1, 1, 2, 2, 1, 2, 2, 3, 3, 2, 6]
[0, 1, 1, 2, 2, 1, 2, 2, 3, 3, 2, 3]

import java.util.*;


public class Solution {
    /**
     * 最少货币数
     * @param arr int整型一维数组 the array
     * @param aim int整型 the target
     * @return int整型
     */
   public int minMoney(int[] arr, int aim) {
        int max = aim + 1;
        int[] dp = new int[aim + 1];
        Arrays.fill(dp, max);
        dp[0] = 0;
        for (int i = 0; i < arr.length; i++) {
            for (int j = arr[i]; j <= aim; j++) {
                if (arr[i] <= j) {
                    dp[j] = Math.min(dp[j], dp[j - arr[i]] + 1);
                }
            }
        }

        if(dp[aim]==aim+1){
            return -1;
        }
        return dp[aim];
    }
}