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)