1、题目描述
Given a string s and a dictionary of words dict, determine if s can be segmented into a space-separated sequence of one or more dictionary words.
For example, given
s = "leetcode"
,
dict = ["leet", "code"]
.
Return true because "leetcode"
can be segmented as "leet code"
.
最常用的算法是穷举法,即从第一个字母开始,判断形成的单词是否在dict中。
如果在,继续向后遍历。如果不在,继续向后扩大搜索范围,直到形成在dict中的单词。如果到最后一直没有,返回false。
bool wordBreak(string s, unordered_set<string> &dict) {
if(dict.find(s) != dict.end()){
return true;
}
bool finished = false;
for(int i = 1; i< s.length(); i++){
string first = s.substr(0, i);
if(dict.find(first)!=dict.end()){
if(i == s.length()){
finished = true;
}else{
string second = s.substr(i);
finished = wordBreak(second, dict);
if(finished){
break;
}
}
}
}
return finished;
}
之前找到过的词,并没有被记录,也就是没有记忆的。
超时的case:
Last executed input: | "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab", ["a","aa","aaa","aaaa","aaaaa","aaaaaa","aaaaaaa","aaaaaaaa","aaaaaaaaa","aaaaaaaaaa"] |
需要逐步搜索,因此时间复杂度为O(n^2)这个显然没有被accepted。
外层第一次遍历,a在dict中,进入递归,一直到b不在词典中,遍历失败。并且每一次都需要这样的尝试。
需要执行第二次遍历,aa在词典中,进入递归,一直到ab不在词典中。
3、分析思路2
采用递归的思想,将前面能够在词典中的单词,都记录下来到一个数组中。
bool wordBreak(string s, unordered_set<string> &dict) {
size_t nsize = s.size();
int i=0,j=0;
bool *dp = new bool[nsize];
memset(dp,false,sizeof(dp));
for(i=0;i<nsize;++i)
{
dp[i] = ((dict.find(s.substr(0,i+1))!=dict.end()) ? true : false);
if(dp[i])
{
continue;
}
else
{
for(j=0;j<i;++j)
{
if(dp[j])
{
dp[i] = ((dict.find(s.substr(j+1,i-j))!=dict.end())?true:false);
if(dp[i])
{
break;
}
}
}
}
}
bool result = dp[nsize-1];
delete []dp;
return result;
}
时间复杂度O(n*n),因为辅助数组的存在,之前判断过了就不需要重新判断了。轻松accepted。