题目
给定一组单词words,编写一个程序,找出其中的最长单词,且该单词由这组单词中的其他单词组合而成。若有多个长度相同的结果,返回其中字典序最小的一项,若没有符合要求的单词则返回空字符串。
示例:
输入: [“cat”,“banana”,“dog”,“nana”,“walk”,“walker”,“dogwalker”]
输出: “dogwalker”
解释: "dogwalker"可由"dog"和"walker"组成。
提示:
0 <= len(words) <= 200
1 <= len(words[i]) <= 100
思路
排序, 从长到短, 等长按字典序A < B
, 动规d[i] = 1当且仅当前缀串x[0...i - 1]
可由words的集合set中的单词构成.
关键函数是动规部分, 分两种情况讨论(注意是完备的划分),
x[0...i - 1]
直接能成字符串则d[i]赋值为1,- 不能直接找到匹配的字符串, 则取前缀串的两段划分,
x[0...j]
是一个字符串,x[j + 1...i - 1]
是一种字符串时, d[i] = 1.
代码
class Solution {
public:
int d[200 + 5];
struct cmp{
bool operator()(const string& A, const string& B){
return A.size() > B.size() || (A.size() == B.size() && A < B);
// longer is higher priority and smaller dictionary order is higher priority when two strings have same length
}
};
string longestWord(vector<string>& words) {
unordered_set<string> S(words.begin(), words.end());
sort(words.begin(), words.end(), cmp());
for(auto x: words){
if(x.empty()) continue;
memset(d, 0, sizeof(d));
if(dyn(x, S)) return x;
}
return ""; // no answer
}
bool dyn(const string& x, const unordered_set<string>& S){
for(int i = 0; i < x.size(); i++){
if(i < x.size() - 1){
string suba = x.substr(0, i + 1);
if(S.count(suba)) d[i] = 1;
}
for(int j = 0; j < i; j++){
if(!d[j]) continue;
string subb = x.substr(j + 1, i - j);
if(S.count(subb)){
d[i] = 1;
break;
}
}
}
return d[x.size() - 1];
}
};
总结
(1) string.substr(start, length)
(2) for(auto x: nums)类似python中的for i in range(n)的用法
(3) set.count(string)在set中查找string