leetcode p139:word break
给定一个字符串s和一个字典dict,判断该字符串是否可以由字典中单词组成。
举个栗子:
s = “leetcode”
dict = [“leet”, “code”]
s可以由dict中单词组成,所以返回true。
注意!
栗子2:
input:
"abcd"
["a","abc","b","cd"]
output:
true
动态规划解法:
用f[i]表示前i个字符是否在字典中,则
f[i] = true, if i == 0 || (f[j-1] == true && s.substr(j,i-j+1)在dict中)
最后判断f[s.size()-1]是否为真,若真则该字符串可以由字典中单词组成;若假则不可以。
代码:
class Solution {
public:
bool wordBreak(string s, unordered_set<string>& wordDict) {
int n = s.size();
vector<bool> f(n, false);
for (int i=0; i<n; ++i) {
for (int j=i; j>=0; --j) {
if (j == 0 || f[j-1]) {
string word = s.substr(j, i-j+1);
if (wordDict.find(word) != wordDict.end()) {
f[i] = true;
}
}
}
}
return f[n-1];
}
};
可以优化的地方:若dict比较小,可以先计算出字典中单词的最小长度minL和最大长度maxL,在遍历计算f[i]时可以不遍历所有子字符串,而是只遍历长度在[minL,maxL]范围内的子串即可。
优化后的代码如下:
class Solution {
public:
bool wordBreak(string s, unordered_set<string>& wordDict) {
int n = s.size();
vector<bool> f(n, false);
int maxL = 0, minL = n;
for (auto str: wordDict) {
maxL = str.size()>maxL ? str.size() : maxL;
minL = str.size()<minL ? str.size() : minL;
}
for (int i=0; i<n; ++i) {
for (int j=i-minL+1; j>=0 && i-j+1 <= maxL; --j) {
if (j == 0 || f[j-1]) {
string word = s.substr(j, i-j+1);
if (wordDict.find(word) != wordDict.end()) {
f[i] = true;
break;
}
}
}
}
return f[n-1];
}
};
优化前
Run time : 16ms优化后
Run time: 3ms