心得:
第一题背包问题,之前用斐波那契数列的方法做过,其实也可以转换为完全背包。
注意初始化:既然递归公式是 dp[i] += dp[i - j],那么dp[0] 一定为1,dp[0]是递归中一切数值的基础所在,如果dp[0]是0的话,其他数值都是0了。
第二题、重点:完全背包在于其物品无线,所以遍历顺序是怎么样的,而不是递推公式!!!
这道题要求最少硬币数,因此递推公式dp[j] = min(dp[j - coins[i]] + 1; dp[j])
第三题:想不清楚的就是平方数也能够该怎么表示出来,其实在遍历物品的时候,用i * i <= n,然后在递推公式中用dp[j - i * i]就可以了。
第一题 爬楼梯 LeetCode 70 https://leetcode.cn/problems/climbing-stairs/description/
假设你正在爬楼梯。需要 n
阶你才能到达楼顶。
每次你可以爬 1
或 2
个台阶。你有多少种不同的方法可以爬到楼顶呢?
示例 1:
输入:n = 2 输出:2 解释:有两种方法可以爬到楼顶。 1. 1 阶 + 1 阶 2. 2 阶
dp定义:台阶数为n,有dp[n]种方法上去。
递推公式:dp[i] += dp[i - j]
初始化:既然递归公式是 dp[i] += dp[i - j],那么dp[0] 一定为1,dp[0]是递归中一切数值的基础所在,如果dp[0]是0的话,其他数值都是0了。
遍历顺序:是排列,所以先背包后物品。从左到右
class Solution {
public:
int climbStairs(int n) {
vector<int> dp(n + 1, 0);
dp[0] = 1;
for(int i = 1; i <= n; i++){
for(int j = 1; j <= 2; j++){
if(i >= j) dp[i] += dp[i - j];
}
}
return dp[n];
}
};
第二题、零钱兑换 LeetCode 322 https://leetcode.cn/problems/coin-change/description/
给你一个整数数组 coins
,表示不同面额的硬币;以及一个整数 amount
,表示总金额。
计算并返回可以凑成总金额所需的 最少的硬币个数 。如果没有任何一种硬币组合能组成总金额,返回 -1
。
你可以认为每种硬币的数量是无限的。
示例 1:
输入:coins =[1, 2, 5]
, amount =11
输出:3
解释:11 = 5 + 5 + 1
dp数组含义:dp[]
递推公式:重点:完全背包在于其物品无线,所以遍历顺序是怎么样的,而不是递推公式!!!
这道题要求最少硬币数,因此递推公式dp[j] = min(dp[j - coins[i]] + 1; dp[j])
初始化:首先凑足总金额为0所需钱币的个数一定是0,那么dp[0] = 0;
考虑到递推公式的特性,dp[j]必须初始化为一个最大的数,否则就会在min(dp[j - coins[i]] + 1, dp[j])比较的过程中被初始值覆盖。所以下标非0的元素都是应该是最大值。
遍历顺序:本题求钱币最小个数,那么钱币有顺序和没有顺序都可以,都不影响钱币的最小个数。
所以本题并不强调集合是组合还是排列。
如果求组合数就是外层for循环遍历物品,内层for遍历背包。
如果求排列数就是外层for遍历背包,内层for循环遍历物品。
class Solution {
public:
int coinChange(vector<int>& coins, int amount) {
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++){
if(dp[j - coins[i]] != INT_MAX){
dp[j] = min(dp[j - coins[i]] + 1, dp[j]);
}
}
}
if(dp[amount] == INT_MAX) return -1;
return dp[amount];
}
};
第三题、完全平方数 LeetCode279 https://leetcode.cn/problems/perfect-squares/description/
给你一个整数 n
,返回 和为 n
的完全平方数的最少数量 。
完全平方数 是一个整数,其值等于另一个整数的平方;换句话说,其值等于一个整数自乘的积。例如,1
、4
、9
和 16
都是完全平方数,而 3
和 11
不是。
示例 1:
输入:n =12
输出:3 解释:12 = 4 + 4 + 4
这一题让我想不清楚的就是平方数也能够该怎么表示出来,其实在遍历物品的时候,用i * i <= n,然后在递推公式中用dp[j - i * i]就可以了。
dp数组:到达j这个数需要的最少平方数个数
递推公式:dp[j] = min(dp[j - i * i] + 1, dp[j])
初始化:dp[0] = 0
遍历顺序:先物品后背包(反过来其实也可以)
class Solution {
public:
int numSquares(int n) {
vector<int> dp(n + 1, INT_MAX);
dp[0] = 0;
// for(int i = 1; i * i <= n; i++){
// for(int j = 1; j <= n; j++){
// }
// }
for(int i = 1; i * i <= n; i++){
for(int j = i * i; j <= n; j++){
dp[j] = min(dp[j - i * i] + 1, dp[j]);
}
}
return dp[n];
}
};