1.完全背包解决爬楼梯问题
1.爬楼梯抽象成背包问题就是:物品有1和2,而背包容量有n个,算出不同的排列结果。因为走楼梯能在1格和2格之间任意选,这样是完全背包的理由;并且每一次走楼梯是有顺序的,因此它涉及的问题是排列问题。
2.那么我们知道是完全背包的排列问题,只需要先遍历背包再遍历物件就能求出所有的结果,该题的思路依然是:走到j位置必须是走到j-1位置和走到j-2位置方法的和
class Solution {
public:
int climbStairs(int n) {
vector<int> dp(n+1,0);
dp[0]=1;
for(int j=0;j<=n;j++)
{
for(int i=1;i<=2;i++)
{
if(j>=i)
dp[j]+=dp[j-i];
}
}
return dp[n];
}
};
2.零钱兑换
1.dp数组的含义:dp[j]指j位置下,最小数量能符合背包容量的个数。
2.dp数组的条件:针对i物件时,dp[j]=dp[j-coins[i]]+1,那么既然需要找的是最少数量的方法,那么条件就dp[j]=min(dp[j],dp[j-coins[i]]+1);
3.初始化:由条件知道dp[0]=0,此外由于我们求的是最小值,那么数组除0外的其他位置都不能初始化为0;因为如果是0,dp[j]=min(dp[j],dp[j-coins[i]]+1),不管怎么更新初始化的值都会影响条件的生成,那么我们初始化其他的位置为amount+1,这样就不会干扰到其他位置的条件了。
4.本题考虑的是结果的个数。之前讲过的完全背包有组合和排列的问题其实就不需要考虑,因为不论组合还是排列,最少的个数都是一样的结果。不过组合能够优化一部分效率就是了,因为他们不需要考虑比排列多的那些情况。
class Solution {
public:
int coinChange(vector<int>& coins, int amount) {
vector<int>dp(amount+1,amount+1);
dp[0]=0;
for(int i=0;i<coins.size();i++)
{
for(int j=coins[i];j<=amount;j++)
{
dp[j]=min(dp[j],dp[j-coins[i]]+1);
}
}
if(dp[amount]==amount+1)
return -1;
return dp[amount];
}
};
3.完全平方数
1.本题的dp数组含义与上一题基本一致:dp[j]指j位置下,最小数量能符合背包容量的个数
2.dp数组的条件:首先我们遍历的是i,但是条件中需要的是完全平方数,所以物件就是i*i,针对i物件时,dp[j]=dp[j-i*i]+1,那么既然需要找的是最少数量的方法,那么条件就dp[j]=min(dp[j],dp[j-i*i]+1)
3.当考虑dp[0]时,没有数能代表,所以dp[0]=0;此外由于我们求的是最小值,那么数组除0外的其他位置都不能初始化为0,所以由于1恰好也是完全平方数,那最保守的结果也全是1的结果,自然种类有n个。那么我们初始化其他位置的dp数组为n即可
4.遍历的写法问题:首先物件i的遍历,由于我们不能确定n到底是不是完全平方数,那么考虑范围的时候自然要把n带上,所以i<=n;遍历背包时,j的初始值应该为i*2,因为我们刚刚理解到其实i*i才是物件。
class Solution {
public:
int numSquares(int n) {
vector<int>dp(n+1,n);
dp[0]=0;
for(int i=0;i<=n;i++)
{
for(int j=i*i;j<=n;j++)
{
dp[j]=min(dp[j],dp[j-i*i]+1);
}
}
return dp[n];
}
};
day46
4.单词拆分
1.dp数组的含义:dp[i]为i位置下,是否有满足条件的字符能组成0到i位置的字符串。如果有则是true。反之为false
2.首先,并不是只要找到符合背包的局部字符串能对上的字符串就算成功的,字符串的组合是有先后顺序的,那么考虑遍历顺序时应该使用先遍历背包再遍历物件的方法进行排列找结果
3.对于单个的字符串符合的条件:当前位置为j,之前的位置为i。由于是从前向后顺序判别的,假设i位置的值判断已经为true,说明i位置符合要求能找到对应上的值,那么我们只需要在要找的字符串[i,j]位置上判断是否有同样存在的字符串组合,那么我们就能得到dp[j]也是true
class Solution {
public:
bool wordBreak(string s, vector<string>& wordDict) {
unordered_set<string> wordSet(wordDict.begin(), wordDict.end());
vector<bool>dp(s.size()+1,false);
dp[0]=true;
for(int j=0;j<=s.size();j++)
{
for(int i=0;i<j;i++)
{
string word = s.substr(i,j-i);
if(wordSet.find(word)!=wordSet.end()&&dp[i])
dp[j]=true;
}
}
return dp[s.size()];
}
};