动态规划的发展流程:递归的暴力解法 -> 带备忘录的递归解法 -> 非递归的动态规划解法
通过暴力解法,要写出状态转移方程,再使用备忘录或者DP table来优化,
备忘录递归解法既是自上而下
非递归动态规划既是自下而上
动态规划问题中最难的就是写出状态转移方程
斐波那契数列问题只是简单的螺旋上升问题,而动态规划问题需要设计到子问题求解是学max或者min
力扣332 零钱兑换问题
class Solution {
public:
int coinChange(vector<int>& coins, int amount) {
vector<int>his(amount+1,amount+1);
his[0]=0;
for(int i=1;i<=amount;i++)
{
// cout<<i<<endl;
for(int j=0;j<coins.size();j++)
{
if(i<coins[j])
continue;
if(his[i]>his[i-coins[j]]+1)
his[i]=his[i-coins[j]]+1;
}
//cout<<his[i]<<endl;
}
return his[amount]>amount?-1:his[amount];
}
};
i从1到target建立备忘录 DB table
对于每个需要建立写入table的i,尝试每种硬币面值:如果面值大于i,则跳过,再尝试下个面值;如果面值小于i,table[i-面值]+1即为可以兑换硬币的一种方法所得到硬币数量。尝试了所有硬币面值后,得到一种硬币数量最小的方法,将该硬币数量填入table[i];
注意数据结构的设置:
1,table大小为target+1,从table[0]到table[target],分别表示兑换0到target需要的最小硬币数量
2,table表的初始量设为taget+1,因为硬币最小值为1,全部兑换成1的硬币数量为target,如果可以兑换的话,兑换方法得到的硬币数量肯定小于target+1,如果没有兑换方法,target[i]就会等于target+1,这用可以用于判断是否有兑换方法。
3,table[0]=0,兑换0元不需要硬币,这也是动态规划状态转移方程的边界条件。在程序中如果i减去面值刚好剪完,直接找到table[i-面值]=table[0]=0,不需要再对这种情况再做处理。