動態規劃是 求解最優化問題的一種常用策略
零錢兌換 322. 零錢兌換
給定不同面額的硬幣 coins 和乙個總金額 amount。編寫乙個函式來計算可以湊成總金額所需的最少的硬幣個數。如果沒有任何一種硬幣組合能組成總金額,返回 -1。
你可以認為每種硬幣的數量是無限的。
示例 1:
輸入:coins = [1, 2, 5], amount = 11
輸出:3
解釋:11 = 5 + 5 + 1
示例 2:
輸入:coins = [2], amount = 3
輸出:-1
示例 3:
輸入:coins = [1], amount = 0
輸出:0
示例 4:
輸入:coins = [1], amount = 1
輸出:1
示例 5:
輸入:coins = [1], amount = 2
輸出:2
貪心只看眼前最優,但不一定得到全域性最優解。如:41 = 25 10 5 1 最優解 20 20 1
如果沒有如下限制
1. 如果面值從1開始,此時一定有解(最壞情況 零錢面值都是1)
則此時如下條件一定可以不滿足: 如果沒有任何一種硬幣組合能組成總金額,返回 -1。( 即如果amount數額湊不齊,返回 -1 )
2. coins 陣列逆序排序
如下解題思路為解決 陣列逆序排序問題,可忽略
陣列逆序排序,需要 int 是包裝型別 integer
1. collections.reverseorder()
// 可以用此方法進行逆序排序,但是int陣列必須是integer包裝類 型別
arrays.sort(coin, collections.reverseorder());
2. 傳入比較器
// 簡寫如下
arrays.sort(coins, (integer f1, integer f2) -> f2 - f1); // 傳入比較器,逆序排序
即arrays.sort(coins,(integer f1,integer f2)->);
當然可以先將其轉為包裝類
integer coin = new integer[coins.length];
for (int i = 0; i 如果沒有如下限制
1. 如果沒有任何一種硬幣組合能組成總金額,返回 -1。( 即如果amount數額湊不齊,返回 -1 )
參考 斐波那契
// 此處類別 fib 1. fib有2個選項 零錢兌換有4個選項 2.都有重複計算--記憶化搜尋 優化
static int fib(int n)
/**
* 暴力遞迴(自頂向下的呼叫,出現了重疊子問題)
** 貪心策略得到的並非最優解 只看眼前
** dp(20) 湊到20分需要的最少硬幣個數
** dp(41) 湊到41分需要的最少硬幣個數
** dp(n) 湊到n分需要的最少硬幣個數
** 第一次選擇了25分的硬幣,現在還差 n-25分
* dp[n-25]湊到n-25需要的最少硬幣個數
* 如果第一次選擇的了25分的硬幣,那麼 dp(n)=dp(n-25)+1 // +1,已經選擇了1枚硬幣,25分的硬幣
*/static int coinchange2_(int n)
/**
* 記憶化搜尋(自頂向下的呼叫)
* dp[1]=dp[5]=dp[20]=dp[25]=1 湊夠1、5、20、25分需要的最少硬幣個數都是 1 枚
*/static int coinchange2(int n) ;
for (int face : faces)
return coinchange2(n, dp);
}static int coinchange2(int n, int dp)
return dp[n]; // 已經算過,直接返回。記憶化搜尋
}// 此處類別 fib 1. fib有2個選項 零錢兌換有4個選項 2.都有重複計算--記憶化搜尋 優化
static int fib(int n)
[ 效能分析 ]
如果沒有如下條件限制
1. 如果沒有任何一種硬幣組合能組成總金額,返回 -1。( 即如果amount數額湊不齊,返回 -1 )
/*
dp[n] 湊夠n分需要的最少硬幣個數
dp[i]=min+1
解讀:dp[i] 湊夠i分需要的最少硬幣個數 = 湊夠 最小個數,再+1個硬幣
coins=
amount=5 dp=[0, 0, 0, 0, 0, 1]
amount=6 dp=[0, -2147483648, -2147483648, -2147483648, -2147483648, 1, -2147483647]
*/static int coinchange3_1(int coins,int amount)
dp[i]=min+1;
}system.out.println(arrays.tostring(dp));
return dp[amount];
}
// dp[n] 湊夠n分需要的最少硬幣個數
/* // 如果amount數額湊不齊。即:如果沒有任何一種硬幣組合能組成總金額,返回 -1。
coins=
amount=5 dp=[0, -1, -1, -1, -1, 1]
amount=6 dp=[0, -1, -1, -1, -1, 1, -1]
amount=20 dp=[0, -1, -1, -1, -1, 1, -1, -1, -1, -1, 2, -1, -1, -1, -1, 3, -1, -1, -1, -1, 1]
*/static int coinchange3_2(int coins,int amount) 沒有1,此時dp[1]=-1 dp[1~4]=-1
continue;
int v = dp[i - coin];
// 如果面值不是從1開始,那麼湊夠dp[i]需要的最少硬幣個數v就是-1.即:如果,dp[1~4]=-1
// 如果湊夠dp[i]需要的最少硬幣個數v >=min ,那麼沒有必要更新min.即:如果,amount=20
// v=dp[20-20]=0 (湊夠0分需要0枚);或者那麼v=dp[20-15]=3 (湊夠15分需要3枚)
// 則 v=3 答案捨棄
if (v < 0 || v >= min) // v=-1 即沒法湊
continue;
min = v;
}if (min == integer.max_value) else
}system.out.println(arrays.tostring(dp));
return dp[amount];
}
// 看不懂如上沒關係,哈哈,讀者可直接看如下
/*
假如有coins= 需要 湊夠 20
1.第乙個continue 過濾 湊夠 1-4
2.第二個continue 過濾 湊夠 6-9 11-14 16-19
v >= min 繼續過濾 湊夠15 需要3,但是用20湊夠20需要0
*/// dp[n] 湊夠n分需要的最少硬幣個數
/* // 如果amount數額湊不齊。即:如果沒有任何一種硬幣組合能組成總金額,返回 -1。
coins=
amount=6 dp=[0, -1, -1, -1, -1, 1, -1]
amount=12 dp=[0, -1, -1, -1, -1, 1, -1, -1, -1, -1, 1, -1, -1]
*/// _322_零錢兌換
static int coinchange(int coins,int amount) 沒有1,此時dp[1]=-1 dp[1~4]=-1
continue;
int v = dp[i - coin];
// v < 0 即沒辦法湊; 即 dp[6~9] dp[11~14] dp[16~19] ;
// v >= min已經有更優解; 即 先用20湊夠20需要0;用15湊夠20還需要5 需要3
if (v < 0 || v >= min)
continue;
min = v;
}if (min == integer.max_value) else
}system.out.println(arrays.tostring(dp));
return dp[amount];
}
[ 效能分析 ]
零錢兌換 leetcode
思路 建乙個動態陣列dp,大小為amount 1,dp裡面的值初始化為amount 1。dp i 表示總金額i最少可以用dp i 的零錢兌換,如果coins j 比i小,那麼總金額i可以由dp i conis j 再加上這枚零錢構成,dp i min dp i dp i coins j 1 如果dp...
leetcode零錢兌換
1.遞迴 回溯 記錄每種錢幣能夠使用的最大數量,然後遍歷每一種情況,求錢幣數量最小的,但會超時 2.動態規劃 設定dp amount 1 初始值設為0x3f3f3f3f,即為無窮大 dp i 表示總量是i是,coins中的金幣組成i所需的最小金幣個數 此處以錢幣為1 2 5,總額是11舉例 dp 1...
LeetCode 零錢兌換
q 給定不同面額的硬幣 coins 和乙個總金額 amount。編寫乙個函式來計算可以湊成總金額所需的最少的硬幣個數。如果沒有任何一種硬幣組合能組成總金額,返回 1。示例 1 輸入 coins 1,2,5 amount 11 輸出 3 解釋 11 5 5 1 示例 2 輸入 coins 2 amou...