题目要求:
Given a string s and a dictionary of words dict, add spaces in s to construct a sentence where each word is a valid dictionary word.
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"]
.
首先,确定一个字符串是否可以拆分,动态规划解决。
在面临要输出所有的可行解的时候,需要使用一个备忘录记录下每一步的前驱结点。(即记录下每个单词的前一个单词的位置)。因为前一个单词可能不唯一,最大的个数为n(总共n个位置)。
注:对于第i个位置而言,判断s[0...i]是否可分,如果该单词本身就在字典中,那么它的前驱index是-1,如果s[j ... i - 1]是一个合法的单词,并且s[0 ... j - 1 ]也是合法的单词,那么它的前驱index应该是 j - 1 ,以此类推,每个位置的前驱节点的个数至多为n。由于上述出现了-1这个负数,那么我们定义s的下标从1开始。即下述“第i个字符”表示s[i-1].因此,定义二维数组备忘录tbl[n+1][n],其中tbl[i]表示第i个字符的所有的前驱结点的index的集合。
代码:
class Solution {
public:
vector<string> wordBreak(string s, unordered_set<string> &dict)
{
vector<string> ret;
if(s.empty())
return ret;
int len = s.length();
vector<vector<int> > tbl(len + 1, vector<int>());
GenerageTable(s, dict, tbl);
string path;
dfs(s, tbl, ret, path, len);
return ret;
}
//创建tbl记录 记录所有以i点为结尾的分割的位置,如果不能那么tbl[i]为空,如果可以就记录起始位置的位置
void GenerageTable(const string& s, unordered_set<string>& dict,
vector<vector<int> >& tbl)
{
int len = s.size();
vector<bool> flag(len + 1, false);
flag[0] = true;
for (size_t i = 1; i <= len; ++i) {
for (size_t j = 0; j < i; ++j) {
if(flag[j] && dict.count(s.substr(j, i - j)) != 0)
{
tbl[i].push_back(j);
flag[i] = true;
}
}
}
}
//递归的寻找符合要求的字符串分割方法并将结果存入ret中
void dfs(const string& s, vector<vector<int> >& tbl, vector<string>& ret, string& path, int step)
{
if(step == 0)
ret.push_back(path);
if (tbl[step].size()) {
for(size_t i = 0; i < tbl[step].size(); ++i)//递归求解所有可以以step点结尾的分割
{
string tmp = path;
if(!path.empty())
path = ' ' + path;//save the break word using space to seperate it.
path = s.substr(tbl[step][i], step - tbl[step][i]) + path;
dfs(s, tbl, ret, path, tbl[step][i]);
path = tmp;//递归返回的时候回复path,进入下一次循环
}
}
}
};