【LeetCode 30】串联所有单词的子串
【题解】
开个字典树记录下所有的单词。 然后注意题目的已知条件 每个单词的长度都是一样的。 这就说明不会出现某个字符串是另外一个字符串的前缀的情况(除非相同). 所以可以贪心地匹配(遇到什么字符就在字典树里面沿着边从根往下走就好). 假设给的单词的个数为len.(每个单词的长度都是L) 显然从每个位置开始都要匹配len次。而且每次都要匹配L个字符。 然后因为可能会出现一个单词出现多次的情况。 那么你得记录一下之前某个单词用了多少次。【代码】
class Solution {
public:
int tree[100000][26+5],tot;
int tag[100000];
int used[100000];
vector<int> visits;
vector<int> findSubstring(string s, vector<string>& words) {
vector<int> ans;ans.clear();
if (s=="" || words.empty()) return ans;
memset(tree,0,sizeof tree);
memset(tag,0,sizeof tag);
tot = 1;
int lendic = words.size();
for (int i = 0;i < lendic;i++){
if (i>0 && ((int)words[i].size()!=(int)words[0].size())) return ans;
string ts = words[i];
int len2 = ts.size();
int p = 1;
for (int j = 0;j < len2;j++){
if (tree[p][ts[j]-'a']==0){
tree[p][ts[j]-'a'] = ++tot;
}
p = tree[p][ts[j]-'a'];
}
tag[p]++;
}
int L = words[0].size();
int len = s.size();
for (int i = 0;i < len;i++){
bool ok = true;
visits.clear();
for (int j = 0;j < lendic;j++){//要匹配字典里面的单词个数次
int p = 1;
for (int k = i+j*L;k < i+(j+1)*L;k++){//每次匹配的长度是固定的
if (k>=len){
ok = false;
break;
}
if (tree[p][s[k]-'a']==0){
ok = false;
break;
}
p = tree[p][s[k]-'a'];
}
if (!ok) break;
if (tag[p]==0) { ok=false;break;}//如果字典里没有这个单词就停止
if (used[p]==0) visits.push_back(p);//记录一下哪些位置用到了,之后清0用
used[p]++;
if (used[p]>tag[p]){//如果用的次数超过单词的个数了,则不行。
ok = false;
break;
}
}
for (int x:visits) used[x]=0;
if (ok) ans.push_back(i);
}
return ans;
}
};