139. 单词拆分
给定一个非空字符串 s 和一个包含非空单词的列表 wordDict,判定 s 是否可以被空格拆分为一个或多个在字典中出现的单词。
说明:
- 拆分时可以重复使用字典中的单词。
- 你可以假设字典中没有重复的单词。
示例 1:
输入: s = "leetcode", wordDict = ["leet", "code"]
输出: true
解释: 返回 true 因为 "leetcode" 可以被拆分成 "leet code"。
示例 2:
输入: s = "applepenapple", wordDict = ["apple", "pen"]
输出: true
解释: 返回 true 因为 "applepenapple" 可以被拆分成 "apple pen apple"。
注意你可以重复使用字典中的单词。
示例 3:
输入: s = "catsandog", wordDict = ["cats", "dog", "sand", "and", "cat"]
输出: false
-
思路
因为说明中告诉我们可以重复使用字典中的单词,所以我们只需要关注字符串s的状态即可。
可以通过DP一维数组维护前i串是否恰好可以被分成字典中出现的单词。
d p [ i ] = d p [ i − l e n ] & & ( s u f f e r [ i − l e n + 1 ] = = w o r d D i c t [ j ] ) dp[i]=dp[i-len] \&\& (suffer[i-len+1]==wordDict[j]) dp[i]=dp[i−len]&&(suffer[i−len+1]==wordDict[j])
suffer数组记录前缀字符串,可以直接打表实现。 -
代码
class Solution { public: bool dp[201]; bool wordBreak(string s, vector<string>& wordDict) { int n=wordDict.size(); string ss[201][201]; //记录各个区间下的字符串 for(int i=0;i<s.size();i++){ string q = ""; for(int j=i;j<s.size();j++){ q += s[j]; ss[i][j] = q; } } for(int i=0;i<s.size();i++){ for(int j=0;j<n;j++){ int len = wordDict[j].size(); if(i>=len-1){ if(ss[i-len+1][i]==wordDict[j]){ if(i-len<0) dp[i] = true; else dp[i] = dp[i-len]; } if(dp[i]) break;//当前成立时直接退出即可。 } } } return dp[s.size()-1]; } };
进阶:
140. 单词拆分 II
给定一个非空字符串 s 和一个包含非空单词列表的字典 wordDict,在字符串中增加空格来构建一个句子,使得句子中所有的单词都在词典中。返回所有这些可能的句子。
说明:
- 分隔时可以重复使用字典中的单词。
- 你可以假设字典中没有重复的单词。
示例 1:
输入:
s = "catsanddog"
wordDict = ["cat", "cats", "and", "sand", "dog"]
输出:
[
"cats and dog",
"cat sand dog"
]
示例 2:
输入:
s = "pineapplepenapple"
wordDict = ["apple", "pen", "applepen", "pine", "pineapple"]
输出:
[
"pine apple pen apple",
"pineapple pen apple",
"pine applepen apple"
]
解释: 注意你可以重复使用字典中的单词。
-
思路
思路与第一题差不多,但这里我们需要记录所有的可能情况,那可以确定需要使用回溯法解决。
这里利用DFS从后往前依次查找前缀字符串,并记录即可。
其中前缀字符串与字典中的word匹配可用集合优化。
-
代码
class Solution { public: bool dp[201]; string ss[201][201]; vector<string> v; set<string> word; vector<string> wordBreak(string s, vector<string>& wordDict) { int n=wordDict.size(); //记录各个区间下的字符串 for(int i=0;i<s.size();i++){ string q = ""; for(int j=i;j<s.size();j++){ q += s[j]; ss[i][j] = q; } } for(int i=0;i<n;i++){ word.insert(wordDict[i]); } for(int i=0;i<s.size();i++){ for(int j=0;j<n;j++){ int len = wordDict[j].size(); if(i>=len-1){ if(ss[i-len+1][i]==wordDict[j]){ if(i-len<0) dp[i] = true; else dp[i] = dp[i-len]; } if(dp[i]) break;//当前成立时直接退出即可。 } } } if(dp[s.size()-1]){ dfs(s.size()-1,""); } return v; } void dfs(int x,string ans){//x为当前位置,ans记录匹配符合的字符串 if(x<0) { v.push_back(ans); return; } for(int i=x;i>=0;i--){ if(word.count(ss[i][x])){ if(ans=="") dfs(i-1,ss[i][x]); else dfs(i-1,ss[i][x]+" "+ans); } } } };