1.确定dp数组以及下标的含义
dp[i] : 爬到有i个台阶的楼顶,有dp[i]种方法。
2.确定递推公式
本题中:dp[i] 可以由dp[i-1]、dp[i-2]、dp[i-3]等,即dp[i - j]
递推公式为:dp[i] += dp[i - j]
3.dp数组如何初始化
由递推公式:dp[i] += dp[i - j]得出dp[0] = 1,如果为0无法推了,全部都是0.
4.确定遍历顺序
1步、2步和2步、1步都是上三个台阶,但是是两种方法。
所以需要将target放在外循环,nums放在内循环。
5.举例推导dp数组
class Solution {
public:
int climbStairs(int n) {
vector<int> dp(n + 1, 0); // 初始化动态规划数组
dp[0] = 1; // 边界条件,当 n = 0 时有一种爬楼梯的方法
for(int i = 1 ; i <= n ; i++){ // 遍历台阶数,从1到n
for(int j = 1 ; j <= 2 ; j++){ // 遍历可以选择的步数,1或2
if( i - j >= 0) dp[i] += dp[i - j]; // 状态转移方程,由 dp[i-j] 转移得到 dp[i]
}
}
return dp[n]; // 返回爬到第n个台阶的方案数
}
};
1.确定dp数组以及下标的含义
dp[j] : 凑满总额为j需要钱币的最小个数为dp[j]
2.确定递推公式
凑总额为j - coins[i] 的最小个数为dp[ j - coins[i]] , 加上减去的钱币的个数 dp[j -coins[i]] + 1 就是dp[j]
dp[j] 取所有的的dp[j - coins[i]] + 1中最小的。
递推公式:dp[j] = min(dp[j -coins[i]] + 1 , dp[j])
3.dp数组如何初始化
由递推公式可知,由于是求最小值dp[j]必须初始化为一个最大的数,否则在min中被初始值覆盖。
vector<int> dp(amount + 1 , INI_MAX);
dp[0] = 0;
4.确定遍历顺序
如果求组合数外层for循环物品,内层for循环背包。
如果求排列数外层for循环背包,内层for循环物品。
class Solution {
public:
int coinChange(vector<int>& coins, int amount) {
// 初始化dp数组,将0元的硬币兑换方法设置为0,其他的为INT_MAX
vector<int> dp(amount + 1, INT_MAX);
dp[0] = 0;
// 遍历硬币数组,每个硬币作为物品
for (int i = 0; i < coins.size(); i++) {
// 遍历背包容量,从硬币面值开始遍历,因为小于硬币面值的金额无法使用该硬币兑换
for (int j = coins[i]; j <= amount; j++) {
// 如果dp[j - coins[i]]是初始值则跳过,否则更新dp[j]
if (dp[j - coins[i]] != INT_MAX) {
dp[j] = min(dp[j - coins[i]] + 1, dp[j]);
}
}
}
// 如果dp[amount]仍为初始值,说明无法使用硬币兑换成目标金额
if (dp[amount] == INT_MAX) {
return -1;
}
return dp[amount];
}
};
1.确定dp数组以及下标的含义
dp[j]:和为j的完全平方数的最小数量为dp[j]
2.确定递推公式
dp[j]可以由dp[j - i * i]推出,dp[j - i * i] + 1可以凑成dp[j]
需要选择最小的dp[j]
递推公式为:dp[j] = min(dp[j - i * i]+ 1, dp[j]);
3.dp数组如何初始化
由递推公式dp[j] = min(dp[j - i*i]+1,dp[j])可知每次选择最小的,故非0下标的dp[j]一定要初始为最大值,这样dp[j]在递推的时候才不会被初始值覆盖。
4.确定遍历顺序
如果求组合数就是外层for循环遍历物品,内层for遍历背包。
如果求排列数就是外层for遍历背包,内层for循环遍历物品。
vector<int> dp(n + 1, INT_MAX);
dp[0] = 0;
for(int i = 0 ; i<=n ; i++){
for(int j = 1; j * j <= i ; j++){
dp[i] = min(dp[i - j*j]+1 ,dp[i]);
}
}
5.举例推导dp数组
class Solution {
public:
int numSquares(int n) {
vector<int> dp(n + 1, INT_MAX); // 初始化dp数组,dp[i]表示组成i所需的最少平方数个数
dp[0] = 0; // 初始化dp[0]为0,表示组成0不需要平方数
for (int i = 1; i <= n; i++) { // 遍历背包,即遍历目标数
for (int j = 1; j * j <= i; j++) { // 遍历物品,即平方数
dp[i] = min(dp[i - j * j] + 1, dp[i]); // 转移方程,dp[i-j*j]+1表示当前数减去一个平方数后,组成剩余数所需的平方数个数+1
}
}
return dp[n]; // 返回组成n所需的最少平方数个数
}
};
[代码随想录]