题意:
给定一个sss串,然后qqq个询问,每个询问给个ttt串(保证ttt串长度<=10)然后把ttt串接到sss串后面,然后求t中的字符的nextnextnext数组(每个询问独立,也就是说每个询问后sss串还是原本的sss串,不会变成s+ts+ts+t)
题解:
先预处理sss串的nextnextnext数组,然后对于每个询问对结尾ttt串跑nextnextnext数组。这是显然的做法,然后TLE了。只要ttt串的数据是正好要跳sss串整个长串的话,每次就是跑1e61e61e6的长度了,这样的话极限时间复杂度是O(q∗∣s∣)O(q*|s|)O(q∗∣s∣),所以会TLE。
然后就是想怎么优化这个kmpkmpkmp。kmpkmpkmp的本质是一颗树(如果每个next[i]next[i]next[i]向iii建边,那么会形成一颗以000为根的树),然后kmpkmpkmp匹配的过程就是一直往父节点跳的过程。那么如果能够跳一次就直接跳到应该匹配的位置就好了,而不是一直跳,然后边跳边判断。
所以引入一个ch[N][26]ch[N][26]ch[N][26]数组。ch[i][j]ch[i][j]ch[i][j]表示iii这个点若匹配字符jjj要会匹配到的位置
那么原先,next[i]匹配过程为:
void get_next(string &s) {
nxt[1] = 0;//下标从1开始
for (int i = 2; i < s.length(); i++) {
nxt[i] = nxt[i - 1];
while (nxt[i] && s[i] != s[nxt[i] + 1])
nxt[i] = nxt[nxt[i]];
if (s[nxt[i] + 1] == s[i])nxt[i]++;
}
}
就变为了
nxt[1] = 0;ch[0][s[1] - 'a'] = 1;
for (int i = 2; i <= n; i++) {
nxt[i] = ch[nxt[i - 1]][s[i] - 'a'];
ch[i - 1][s[i] - 'a'] = i;
for (int j = 'a'; j <= 'z'; j++) {
if (j == s[i])continue;
ch[i - 1][j - 'a'] = ch[nxt[i - 1]][j - 'a'];
}
}
然后附上严格鸽的题解:严格鸽的题解
.下面是我的关键代码
void solve(){
cin>>s+1;
n=strlen(s+1);
nxt[1]=0;ch[0][s[1]-'a']=1;
for(int i=2;i<=n;i++){
int c=s[i]-'a';
nxt[i]=ch[nxt[i-1]][c];
ch[i-1][c]=i;
for(int j='a';j<='z';j++){
if(j==s[i]) continue;
int c=j-'a';
ch[i-1][c]=ch[nxt[i-1]][c];
}
}
int m;cin>>m;
while(m--){
cin>>t+1;
int len=strlen(t+1)+n;
for(int i=n+1;i<=len;i++) s[i]=t[i-n];
for(int i=n+1;i<=len;i++){
int c=s[i]-'a';
nxt[i]=ch[nxt[i-1]][c];
ch[i-1][c]=i;
for(int j='a';j<='z';j++){
if(j==s[i]) continue;
int c=j-'a';
ch[i-1][c]=ch[nxt[i-1]][c];
}
cout<<nxt[i]<<' ';
}cout<<endl;
}
}
本文介绍了一种针对KMP算法的优化方法,通过预处理字符串并构建特殊数组来提高匹配效率。这种方法尤其适用于需要频繁查询的情况,能显著减少运行时间。
2302

被折叠的 条评论
为什么被折叠?



