和LeetCode第 139 题:单词拆分(C++)_zj-CSDN博客差不多,只不过这儿需要输出详细的dp方案,而且是所有的。
所以在139题的基础上:
- 循环遍历的时候不能break出去,因为需要所有的组合信息;
- 增加一个二维数组,记录dp转移的信息
- 根据二维数组得到的转移信息,dfs生成可能的string
class Solution {
public:
vector<string> res;
string tmp = "";
void backtrack(string &s, string tmp, vector<vector<int>> &record, int m){
if(m == s.size()){
res.push_back(string(tmp.begin(), tmp.end()-1));//去掉最后的空格
return;
}
for(int i = 0; i < record[m].size(); ++i){
if(record[m][i] == 1){
backtrack(s, tmp + s.substr(m, i-m) + " ", record, i);
}
}
}
vector<string> wordBreak(string s, vector<string>& wordDict) {
unordered_set<string> wordset;
unordered_set<int> lenset;
for(const auto &word : wordDict){
wordset.insert(word);
lenset.insert(word.size());
}
vector<vector<int>> record(s.size()+1, vector<int>(s.size()+1, 0));//用于记录可达信息
vector<int> dp(s.size()+1, 0);
dp[0] = 1;
for(int i = 1; i <= s.size(); ++i){
for(int j = i-1; j >= 0; --j){//枚举i之前的所有位置
if(!lenset.count(i-j)) continue;//[j,i]长度不合法(没有单词是这个长度)
if(dp[j] && wordset.count(s.substr(j, i-j))){
dp[i] = 1; //这儿不能break出去了,因为需要计算全部的可能组合
record[j][i] = 1;//记录j->i,表示可以从j通过某个单词转移到i
}
}
}
if(dp.back() == 0) return res;//末尾并不可达
backtrack(s, tmp, record, 0);//dfs搜寻所有路径
return res;
}
};
不过上面的二维数组记录可达信息可以不用,在回溯里面进行判断也是可以的:
class Solution {
public:
vector<string> res;
unordered_set<string> wordset;
unordered_set<int> lenset;
vector<string> wordBreak(string s, vector<string>& wordDict) {
for(const auto &w : wordDict) {
wordset.insert(w);
lenset.insert(w.size());
}
vector<int> dp(s.size()+1, 0);
dp[0] = 1;
for(int i = 1; i <= s.size(); ++i){
for(const auto &j : lenset){//遍历所有的单词长度
if(i >= j && dp[i-j] && wordset.count(s.substr(i-j, j))) dp[i] = 1;
}
}
//需要事先判断末尾是否可达,很重要!!!
if(dp.back() == 0) return res;//末尾不可达
backtrack(dp, 0, s, "");
return res;
}
//idx代表上一个可达的位置
void backtrack(vector<int> &dp, int idx, string &s, string tmp){
if(idx == s.size()){
tmp.pop_back();//去掉最后的空格
res.push_back(tmp);
return;
}
//idx为上一个可达位置,初始为0
for(int i = idx+1; i < dp.size(); ++i){//i最开始为1,对应s的首元素
if(dp[i] == 1 && wordset.count(s.substr(idx, i-idx))){//可达并且单词存在
backtrack(dp, i, s, tmp+s.substr(idx, i-idx)+" ");
}
}
}
};