322.零钱兑换二 五步解决完全背包问题 1.设计dp数组,dp数组的下标表示金额,内容表示硬币数量 2.初始化dp数组,dp[0]=0; 3.理清递推公式,dp[i]=min(dp[i-coins[j]]+1,dp[i]);当可以置换更大硬币时,在原有基础上加一 4.遍历顺序判断,置换硬币时组合数,不需要考虑顺序,采用先物品后背包的策略 5.模拟递推过程,可以画图
class Solution {
public:
int coinChange(vector<int>& coins, int amount) {
//采用完全背包解决
//设计dp数组,下标表示金额,dp[i]表示实际的硬币数量
vector<int> dp(amount+1,INT_MAX);
//初始化
dp[0]=0;//对于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 - coins[i]]是初始值则跳过
dp[j] = min(dp[j - coins[i]] + 1, dp[j]);
}
}
//判断是否满足题设并返回
if(dp[amount]==INT_MAX) return -1;
else return dp[amount];
}
};
279,完全平方数问题 与322重点区分点在初始条件变化
class Solution {
public:
int numSquares(int n) {
//同硬币置换问题,使用动态规划
//设计dp数组
vector<int> dp(n+1,INT_MAX);//下标表示数值大小,存贮需要的完全平方数数量
//初始化
dp[0]=0;
//执行递推公式,因为采用组合数,采用先物品再背包的方式
for(int i=1;i*i<=n;i++){//从i=1开始,先遍历物品
for(int j=i*i;j<=n;j++){//遍历背包
dp[j]=min(dp[j-i*i]+1,dp[j]);
}
}
return dp[n];
}
};
139.单词拆分 难点分析 1.使用hash表简化查找操作 2.内外遍历顺序的判断 3.常见错误为遍历背包时忽略背包上上限为s.size()+1
class Solution {
public:
bool wordBreak(string s, vector<string>& wordDict) {
unordered_set<string> wordSict(wordDict.begin(),wordDict.end());//使用hash表实现快速查找
//设计dp数组,数组下标表示字符长度,内容存储true和false
vector<bool> dp(s.size()+1,false);
dp[0]=true;//必须将数组首元素初始化为true
//因为这里是求排列数,所以必须使用先背包后物品的遍历方式
for(int i=1;i<=s.size();i++){//先对背包进行遍历
for(int j=0;j<i;j++){//对物品进行遍历
//递推公式判断
string word = s.substr(j, i - j); //substr(起始位置,截取的个数)
if (wordSict.find(word) != wordSict.end() && dp[j]) {
dp[i] = true;
}
}
}
return dp[s.size()];
}
};