139. 单词拆分
给你一个字符串
s
和一个字符串列表wordDict
作为字典。请你判断是否可以利用字典中出现的单词拼接出s
。**注意:**不要求字典中出现的单词全部都使用,并且字典中的单词可以重复使用。
输入: s = "leetcode", wordDict = ["leet", "code"]
输出: true
解释: 返回 true 因为 "leetcode" 可以由 "leet" 和 "code" 拼接成。
题目当中可以将字符串列表当作物品,字符串s就是背包,最终需要求解单词能否组成字符串s,就是问物品能不能把背包装满
动规五部曲:
- 确定dp数组及下表含义
dp[i]表示组成字符串长度为i的话,dp[i]=true
- 确定递推公式
如果在[j,i]这个区间的子串中出现在字典里&&dp[j]=true,则dp[i]=true
- dp数组初始化
需要将dp[0]=true否则后续的结果将全部为false
- 确定遍历顺序
对于完全背包,如果求组合数就是外层for循环遍历物品,内层for遍历背包;如果求排列数就是外层for遍历背包,内层for循环遍历物品。这道题需要求得是排列,所以外层遍历背包,内层遍历物品。
- 举例推导dp[i]
class Solution {
public boolean wordBreak(String s, List<String> wordDict) {
HashSet<String> word=new HashSet<>(wordDict);
boolean[] dp=new boolean[s.length()+1];
dp[0]=true;
for(int i=1;i<=s.length();i++){
for(int j=0;j<i&&!dp[i];j++){
if(word.contains(s.substring(j,i))&&dp[j]){
dp[i]=true;
}
}
}
return dp[s.length()];
}
}
多重背包忽略了!!!!
背包问题的递推公式:
- 问能否能装满背包(或者最多装多少):
dp[j] = max(dp[j], dp[j - nums[i]] + nums[i]);
- 问装满背包有几种方法:
dp[j] += dp[j - nums[i]]
- 问背包装满最大价值:
dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);
- 问装满背包所有物品的最小个数:
dp[j] = min(dp[j - coins[i]] + 1, dp[j]);
遍历顺序:
01背包——二维dp数组先遍历物品还是先遍历背包都是可以的,第二层是从小到大遍历;一维数组只能先遍历物品再遍历背包,第二层是从大到小
完全背包——如果求组合数就是外层for循环遍历物品,内层for循环遍历背包;如果求排列数就是外层for遍历背包,内层for循环遍历物品。