这周完成的还是Dynamic Programming 部分的题目,这里选择word break系列的两道题目进行分析。
Given a non-empty string s and a dictionary wordDict containing a list of non-empty words, determine if s can be segmented into a space-separated sequence of one or more dictionary words. You may assume the dictionary does not contain duplicate words.
For example, given
s = “leetcode”,
dict = [“leet”, “code”].
Return true because “leetcode” can be segmented as “leet code”.
这道题可以使用动态规划来求解,简单来说,假设dp[i]表示前i个元素组成的序列是否可以正确划分,那么对于一个序列abcdab,长度为6,那么当我们判断abcda都是合法可分符合字典内容时,对于第6个元素:
结合分析的结果可得如下代码:
class Solution {
public:
bool wordBreak(string s, vector<string>& wordDict) {
int len = s.size();
vector<bool> dp(len+1,false);
dp[0] = true;
for(int i = 1; i <= len; i++)
//从前一个元素开始,判断新加入的元素是否存在
for(int j = i-1; j >= 0; j--){
// 判断新加入的元素是否存在
string str = s.substr(j,i-j);
// 新加入的元素和之前的序列都存在时,说明整个序列都存在
if(dp[j] && find(wordDict.begin(),wordDict.end(),str) != wordDict.end()){
dp[i] = true;
break;
}
}
return dp[len];
}
};
Given a non-empty string s and a dictionary wordDict containing a list of non-empty words, add spaces in s to construct a sentence where each word is a valid dictionary word. You may assume the dictionary does not contain duplicate words.
Return all such possible sentences.
For example, given
s = “catsanddog”,
dict = [“cat”, “cats”, “and”, “sand”, “dog”].
A solution is [“cats and dog”, “cat sand dog”].
这道题是上一道题的引申,可以在上一道题的基础上,结合DFS来求解。
结合上述分析可以得到如下代码:
class Solution {
public:
vector<string> wordBreak(string s, vector<string>& wordDict) {
vector<string> res;
if(s.length() == 0 || wordDict.empty()) return res;
// 判断以前i个元素中可以在那些位置划分得到符合条件的一个或多个单词
vector<vector<bool> >dp(s.length()+1, vector<bool>(s.length()));
dp_wordBreak_judge(s, wordDict, dp);
// 得到合法的序列的组合形式
vector<string> tmp;
dp_wordBreak(s, wordDict, res, tmp, dp, s.length());
return res;
}
void dp_wordBreak_judge(string s, vector<string> &wordDict, vector<vector<bool> >&dp){
vector<bool>tmp(s.size()+1,false);
tmp[0] = true;
for(int i = 1; i <= s.size(); i++){
//从前一个元素开始,判断新加入的元素是否存在
for(int j = i-1; j >= 0; j--){
// 判断新加入的元素是否存在
string str = s.substr(j,i-j);
// 新加入的元素和之前的序列都存在时,说明整个序列都存在
if(tmp[j] && find(wordDict.begin(),wordDict.end(),str) != wordDict.end()){
tmp[i] = true;
dp[i][j] = true;
}
}
}
}
void dp_wordBreak(string s, vector<string> &wordDict,
vector<string>&res,vector<string> tmp, vector<vector<bool> >&dp, int cur){
int len = s.length();
if(cur == 0){
string str=tmp[tmp.size()-1];
for(int idx = tmp.size()-2; idx >=0; idx--)
str += " "+tmp[idx];
res.push_back(str);
return ;
}
for(int i = 0; i < len; i++){
// 倒序遍历第一个单词
if(dp[cur][i] == true){
// 得到最后一个单词,继续析取前面的序列
tmp.push_back(s.substr(i,cur-i));
dp_wordBreak(s, wordDict, res, tmp, dp,i);
tmp.pop_back();
}
}
}
};