题目要求:
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,进入下一次循环 } } } };