给出一个字符串s和一个词典,判断字符串s是否可以被空格切分成一个或多个出现在字典中的单词。
您在真实的面试中是否遇到过这个题? Yes
样例
给出
s = “lintcode”
dict = [“lint”,”code”]
返回 true 因为“lintcode”可以被空格切分成“lint code”
思路过程
直观的想法是直接遍历string,有匹配的单词就做一次切分,再去比配剩下的字符串。这样形成了下面的代码
bool wordBreak(string s, unordered_set<string> &dict) {
// write your code here
if(s=="")return true;
if(dict.empty())return false;
int be = 0;
int i;
for(i = 0;i<s.size();i++)
{
string val = s.substr(be,i-be+1);
if(dict.find(val)!=dict.end())be = i+1;
}
if(be == s.size())return true;
return false;
}
但是这样做有情况没有考虑就是如果字典中的单词有前缀情况,例如:如果字典是这样的[“aaaa”,”aaa”]则会出错,再例如无法处理下面的情况
string target = “xyzTLcb”,dict=[“xyz”, “xyzTL,”TLcb”]
总之无论是最短匹配还是最长匹配必须要有一种回溯机制,一旦后面的匹配不正确就能回溯到上一个匹配的单词重新匹配,很容易想到递归的方法。这里采用栈的形式来保存上一个匹配的状态,代码如下:
bool wordBreak(string s, unordered_set<string> &dict){
stack<int> beSave;
stack<int> endSave;
if(s=="")return true;
if(dict.empty())return false;
int be = 0;
for(int i = 0;(!beSave.empty()||i<s.size())&&be<s.size();i++)
{
string val = s.substr(be,i-be+1);
if(dict.find(val)!=dict.end()){
beSave.push(be);
endSave.push(i);
be = i+1;
}
if(i==s.size()&&!beSave.empty()){
be = beSave.top();
i = endSave.top();
beSave.pop();
endSave.pop();
}
}
if(be == s.size())return true;
return false;
}
这里时间复杂度还是比较高的,需要1957ms跑完所有case,以后再优化