算法小菜鸡学习ing
一道很简单的dp动态规划的问题,没想到居然还翻了跟头卡了好久,错误的原因是最初内外层的循环写反了(其实是dp的思路有些问题)。
如果是先遍历所有金额再遍历硬币的数量,在便利过程中你会发现有些amount的dp值会有重复的情况。举个例子:
输入:amount = 5, coins = [1, 2, 5]
输出:4
按照我先遍历amount后遍历coins的情况下:
dp[5]+=dp[5-5];
dp[5]+=dp[4];
dp[5]+=dp[3]
dp[4]中有 +1
1+1+1+1
1+2+1
2+2
dp[3]中有 +2
1+2
1+1+1
这样下来再加上新加入的硬币,就会产生两个重复情况
当交换了内外层循环后:
-
避免重复计算:
- 当外层循环遍历硬币面额时,内层循环遍历金额 amount。这意味着对于每个硬币面额,内层循环会在其对应的金额范围内更新 dp 数组。因为在计算某个金额时,只考虑当前硬币面额及之前的硬币面额,而不会考虑后面的硬币面额。这样确保了每个组合只被计算一次,避免了重复计算。
-
确定 dp 数组的初始值:
- 在动态规划中,通常需要一个初始值来开始计算。对于这个问题,初始值是确保凑齐金额为 0 的硬币组合数为 1。这是因为如果金额为 0,那么不需要任何硬币就可以凑齐,因此硬币组合数为 1。
- 因此,将 dp[0] 设置为 1 是合理的初始值。
- 下面是正确的代码
class Solution {
public:
int dp[10000];
int change(int amount, vector<int>& coins) {
int ans=0;
sort(coins.begin(),coins.end());
dp[0]=1;
if(amount==0)
return 1;
if(amount<coins[0])
return 0;
for(int coin:coins){
for(int i=coin;i<=amount;i++){
dp[i]+=dp[i-coin];
}
}
return dp[amount];
}
};