本道是枚举分割所有字符串,判断是否在字典里出现过。可以使用回溯法 / 完全背包解法
代码随想录第二十七天 | 回溯算法P3 |● 39. ● 40.● 131.-CSDN博客
之前讲解回溯法专题的时候,讲过的一道题目 lc 131,就是枚举字符串的所有分割情况。
lc 131 :是枚举分割后的所有子串,判断是否回文。
本道是枚举分割所有字符串,判断是否在字典里出现过。
单词就是物品,字符串s就是背包,单词能否组成字符串s,就是问物品能不能把背包装满。
拆分时可以重复使用字典中的单词,说明就是一个完全背包!
背包五步曲:
dp[ j ]: 表示 字符串长度为 j , dp [ j ] 为 true 表示其可以拆分为一个或多个字典中的单词
递推:
如果确定dp[j] 是true,且 [j, i] 这个区间的子串出现在字典里,那么dp[i]一定是true。(j < i )。
所以递推公式是 if([j, i] 这个区间的子串出现在字典里 && dp[j]是true) 那么 dp[i] = true。
初始化: 从递推公式中可以看出,dp[i] 的状态依靠 dp[j]是否为true,那么dp[0]就是递推的根基,dp[0]一定要为true,否则递推下去后面都都是false了。其余则均初始化为false, 防止初始值影响递推
遍历顺序,先背包, 再物品
可以看出 i 依赖于 j (j < i) 同时是一个完全背包问题, 从左到右. 问题来了, 先物品 or 先背包?
如果求组合数就是先物品: 外层for循环遍历物品,内层for遍历背包。
如果求排列数就是先背包: 外层for遍历背包,内层for循环遍历物品。
而本题其实我们求的是排列数,为什么呢。 拿 s = "applepenapple", wordDict = ["apple", "pen"] 举例。
"apple", "pen" 是物品,那么我们要求 物品的组合一定是 "apple" + "pen" + "apple" 才能组成 "applepenapple"。
"apple" + "apple" + "pen" 或者 "pen" + "apple" + "apple" 是不可以的,那么我们就是强调物品之间顺序。
所以说,本题一定是 先遍历 背包,再遍历物品。
- class Solution {
- private Set
set; - private int[] memo;
- public boolean wordBreak(String s, List
wordDict) { - set = new HashSet
(wordDict); - memo = new int [s.length()];
- return backtracking(s, 0);
- }
- public boolean backtracking(String s, int startIndex){
- if(startIndex == s.length()){
- return true;
- }
-
- if(memo[startIndex] == -1) {
- return false;
- }
-
- for(int i = startIndex; i < s.length(); i++){
- //当前拆分的子串为[startIndex, i]
- String cur = s.substring(startIndex, i + 1);
- //当前子串不存在于字典中
- if(set.contains(cur) == false){
- continue;
- }
- //存在了, 进入子问题
- if(backtracking(s, i + 1)) return true;
- }
- // 这里是关键,找遍了startIndex~s.length()也没能完全匹配,标记从startIndex开始不能找到
- memo[startIndex] = -1;
- return false;
- }
- }
- class Solution {
- public boolean wordBreak(String s, List
wordDict) { - HashSet
set = new HashSet<>(wordDict); - int [] dp = new int [s.length() + 1];
- dp[0] = 1;
- //先遍历背包
- for(int i = 1; i < s.length() + 1; i++){
- //再遍历物品
- //若当前已经为 1 则 不再修改 / 删去不影响结果
- for(int j = 0; j < i && dp[i] == 0; j++){
- if(set.contains(s.substring(j, i)) && dp[j] == 1){
- dp[i] = 1;
- }
- }
- }
- return dp[s.length()] == 1 ? true : false ;
- }
- }