139. 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"
.
题目解析
这题是求解能否分解成字典里的字符串,即是否问题,找到一个符合的即可。因此我们就开始搜索,想到了之前的回文串动态规划的表达式:f[n] = (f[i],s[i~n]) && f[i]=true
。即,对于每个f[n]
表示能否到达这个位置,遍历前面的位置,如果能到达前面的第i
个位置,那我们就看看字典里是否有s[i~n]
这个字符串,如果有,我们就可以通过这个字符到达当前字符,就可以确认可以到达i
位置了,就不需要继续搜这个位置了。往下搜,能到最后一个位置说明能够分解。
代码
class Solution {
public:
bool wordBreak(string s, vector<string>& wordDict) {
unordered_set<string> ss;
for (auto &i : wordDict)
ss.insert(i);
vector<bool> f(s.size()+1, false);
f[0] = true;
for (int i = 1; i <= s.size(); ++i)
{
for (int j = 0; j < i; ++j)
{
if (f[j])
{
string subs = s.substr(j, i - j);
if (ss.count(subs))
{
f[i] = true;
break;
}
}
}
}
return f[s.size()];
}
};
140. Word Break II
题目
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"]
.
题目解析
看到这个题目,发应过来又是一个深度搜索的问题,构建字符串。好吧,我们开始搜吧。
想法一
这是最直观的深度优先搜索,从起点出发,如果存在字典中字符串,移动一步,然后递归构造结果。over,果不其然超时了,卡在第29个测试用例上,人家可是hard
类型的题目,这么简单的被做出来岂不是很没面子,继续想吧。
代码如下:
class Solution {
public:
void solve(unordered_set<string> &ss,int idx,string s,vector<string> &vs,vector<string> &data)
{
if (idx == s.size())
{
string str;
for (int i = 0; i < data.size() - 1; i++)
{
str += data[i];
str += " ";
}
str += data[data.size() - 1];
vs.push_back(str);
return;
}
for (int i = idx; i < s.size(); ++i)
{
string tmp = s.substr(idx, i - idx + 1);
if (ss.count(tmp))
{
data.push_back(tmp);
solve(ss,i+1,s, vs, data);
data.pop_back();
}
}
}
vector<string> wordBreak(string s, vector<string>& wordDict) {
unordered_set<string> ss;
for (auto &i : wordDict)
ss.insert(i);
vector<string> vs;
vector<string> data;
solve(ss, 0, s, vs, data);
return vs;
}
};
想法二
首先我们是不是递归的时候,遍历的太多,因为很多子串是不存在字典中,因此遍历是无效的。因此,我就想,我给每个位置所可能的后续点生成一个vector
,每个位置只需要遍历这个数组就可以了,但是这个题目还是很顽强啊,还是超时==可能是生成这个vector
花的时间更多吧。
代码如下:
class Solution {
public:
void solve( unordered_map<int, vector<int>> &mii,int idx, string s, vector<string> &vs, vector<string> &data)
{
if (idx == s.size())
{
string str;
for (int i = 0; i < data.size() - 1; i++)
{
str += data[i];
str += " ";
}
str += data[data.size() - 1];
vs.push_back(str);
return;
}
vector<int> d = mii[idx];
for (auto &i:d)
{
string tmp = s.substr(idx, i - idx + 1);
data.push_back(tmp);
solve(mii,i + 1, s, vs, data);
data.pop_back();
}
}
vector<string> wordBreak(string s, vector<string>& wordDict) {
vector<string> vs;
vector<string> data;
unordered_set<string> ss;
for (auto &i : wordDict)
ss.insert(i);
vector<bool> f(s.size() + 1, false);
unordered_map<int, vector<int>> mii;
f[0] = true;
for (int i = 1; i <= s.size(); ++i)
{
for (int j = 0; j < i; ++j)
{
if (f[j])
{
string subs = s.substr(j, i - j);
if (ss.count(subs))
{
f[i] = true;
mii[j].push_back(i - 1);
}
}
}
}
solve(mii,0, s, vs, data);
return vs;
}
};
想法三
哎,很丧气啊,怎么办,不会了。到底是哪里有重复计算了,想破脑壳,想起来前面的看能分解,只需要一个分解就可以了,那反过来,如果一个位置搜索不到结尾,那是不是以后到这个位置就直接不搜索了。对啊,这不就是备忘录方法吗!!!瞧这记性,做完上题忘下题。因此我们使用一个数组来记录每个地方能否到达结尾,一旦到达不了,做一个标记,下次搜到这个位置就不搜索了,好像是减少了不少。
代码如下:
class Solution {
public:
bool solve(unordered_set<string> &ss, int idx, string s, vector<string> &vs, vector<string> &data, vector<bool> &f)
{
if (idx == s.size())
{
string str;
for (int i = 0; i < data.size() - 1; i++)
{
str += data[i];
str += " ";
}
str += data[data.size() - 1];
vs.push_back(str);
return true;
}
if (f[idx] == false)
return false;
bool flag = false;
for (int i = idx; i < s.size(); ++i)
{
string tmp = s.substr(idx, i - idx + 1);
if (ss.count(tmp))
{
data.push_back(tmp);
// 这里注意,要把solve写前面,因为或运算第一个是true就不算后面的
flag = solve(ss, i + 1, s, vs, data, f) || flag;
data.pop_back();
}
}
f[idx] = flag;
return flag;
}
vector<string> wordBreak(string s, vector<string>& wordDict) {
unordered_set<string> ss;
for (auto &i : wordDict)
{
ss.insert(i);
}
vector<string> vs;
vector<string> data;
vector<bool> f(s.size(), true);
solve(ss, 0, s, vs, data,f);
return vs;
}
};
欢迎指正。