动态规划问题的一般形式就是求最值。最显著的特点是最优子结构和重叠子问题。最优子结构就是子问题的最优解,可以从子问题的最优结果推出更大规模问题的最优结果,可以用状态转移方程描述问题。重叠子问题可以通过创建备忘录dp[]避免重复计算。
零钱兑换的解题步骤:
1)先确定状态,也就是原问题和子问题中变化的变量,由于硬币数量可以无限,所以唯一确定的状态就是目标金额amount。
2)然后确定dp函数的定义,当前的目标金额是n,至少需要dp(n)个硬币凑出该金额。
3)确定选择并择优,无论当前的目标金额是多少,选择就是从面额列表coins中选则一个硬币,然后目标金额就会减少。
4)最后明确递归的终止条件,显然目标金额为0时,所需硬币数量为0,而当目标金额小于0时,无解。在动态规划中体现为子问题无解,跳过该次内层循环。
凑零钱问题的状态转移方程如下:
[dp(n)=egin{cases}
0 & n=0 \
-1 & n<0 \
min{dp[n-coin]+1 | coinin coins} & n>0
end{cases}]
int coinChange(vector<int>& coins, int amount) {
vector<int> dp(amount+1, amount+1);
dp[0] = 0;
for(int i = 0; i < dp.size(); i++)
{
for(int coin : coins)
{
if(i-coin < 0)
continue;
dp[i] = min(dp[i], 1+dp[i-coin]);//索引为i-coin的dp[i-coin]加上for循环在这次选出的这个coin(即加1)
}
}
return dp[amount] == amount+1 ? -1 : dp[amount];//为什么要这样返回??当给的coins不能凑出amount时就会出错,比如coins=[2],amount=3,amount无法凑出,此时应返回-1
}