题目内容:
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”.
解题思路:
很直观得想到可以用递归做,代码如下:
class Solution {
public:
bool wordBreak(string s, unordered_set<string>& wordDict) {
return segmentation(s, 0, wordDict);
}
bool segmentation(string &s, int index, unordered_set<string>& wordDict) {
int size(s.size());
if(index == size)
return true;
for(int i = index; i < size; ++i) {
if(wordDict.find(s.substr(index, i-index+1)) != wordDict.end() && segmentation(s, i+1, wordDict))
return true;
}
return false;
}
};
但同样,遇到
“aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab”
[“a”,”aa”,”aaa”,”aaaa”,”aaaaa”,”aaaaaa”,”aaaaaaa”,”aaaaaaaa”,”aaaaaaaaa”,”aaaaaaaaaa”]
这样的输入,会因为很多次的重复运算而超时。
而解决效率问题的做法当然就是动态规划。
动态规划:
需要把问题分解为子问题求解。可以用一个一维数组canSeparate[index]来表示从0到index的字符串能否被分割成字典中的字符。
中间过程的更新方式:
1. 如果从0到index的字符串能够在字典中找到,那么直接返回true;
2. 如果不能找到,那么从当前的index开始向前找到这样一个下标i,使得canSeparate[i]为true,并且字符串[i+1, index]能够在字典中能够找到。
代码如下,运行时间8ms:
class Solution {
public:
bool wordBreak(string s, unordered_set<string>& wordDict) {
int size(s.size());
if(size == 0)
return false;
vector<bool> canSeparate(size, false);
for(int i = 0; i < size; ++i) {
if(wordDict.find(s.substr(0, i+1)) != wordDict.end())
canSeparate[i] = true;
else {
for(int j = i; j > 0; --j) {
if(wordDict.find(s.substr(j, i-j+1)) != wordDict.end() && canSeparate[j-1]) {
canSeparate[i] = true;
break;
}
}
}
}
return canSeparate.back();
}
};