class Solution {
public int DP(int[] arr , int num){
int[] dp = new int[num + 1];
for(int i = 0 ; i < num + 1 ; i++)
dp[i] = -1;
dp[0] = 0;
for(int i = 1 ; i <= num ; i++)
{
int min = -1;
//遍历已经存在的所有面额 ,减去该面额余数是否存在dp[i] (i元拼凑出来的最小硬币数)
//存在则在该数量之上+1
//最终求出最小数量
for(int j = 0 ; j < arr.length ; j++)
{
int tmp = i - arr[j];
if(tmp >= 0 && dp[tmp] != -1)
{
if(min == -1)
{
min = dp[tmp] + 1;
}
else
{
min = Math.min(min,dp[tmp] + 1);
}
}
}
dp[i] = min;
}
return dp[num];
}
public int coinChange(int[] coins, int amount) {
return DP(coins,amount);
}
}
public static boolean existNum(int[] arr,int num){
for(int e : arr)
if(e == num)
return true;
return false;
}
//这种方式会超时
public static int DP1(int[] arr , int num){
int[] dp = new int[num + 1];
for(int i = 0 ; i < num + 1 ; i++)
dp[i] = -1;
dp[0] = 0;
for(int i = 1 ; i <= num ; i++)
{
int min = -1;
//此方式是在遍历之前求出来的每一个dp,在此基础上增加一个硬币
for(int j = 0 ; j < i ; j++)
{
if(dp[j] != -1)
{
if(existNum(arr, i - j))
{
if(min == -1)
{
min = dp[j] + 1;
}
else
{
min = Math.min(min,dp[j] + 1);
}
}
}
}
dp[i] = min;
}
return dp[num];
}
此题目是典型的动态规划问题。
当我们要凑出n块钱
我们可以找出 凑出 n - x 元 的最小硬币数 加上一枚 x 元的硬币 (硬币x必须在我们所拥有的面里面)
此时我们得先求 n -x 元凑出的最小硬币数,并且对不同x得取值是进行比较得到最小数量
如此循环递归下去可能进行了很多此重复得计算而且耗时(比如我们凑出 n - x 可能被计算多次 )
于是我们动态规划逆向求解我们先求出1块钱最小数 依次递增下去 求出n块钱最小硬币数(凑不出来时我们令其为-1)