目的:找出字符串S的全部後綴與字符串T的最長公共前綴,預處理Next[i]。ios
S字符串長度爲n,T字符串長度爲m。c++
Next[i],i∈[0,m),表示T的後綴i與T的最長公共前綴。數組
extend[i],i∈[0,n),表示T與S[i,n)的最長公共前綴。若是有一個extend[i]=m,則T在S中在i位置出現。ide
時間複雜度:O(|S|+|T|)函數
自用模板:加密
#include <iostream> #include <string.h> using namespace std; const int maxn=1100; int Next[maxn],extend[maxn]; void get_Next(char *s) { int n=strlen(s); int i,j,k; for(j=0;1+j<n&&s[j]==s[1+j];j++); Next[1]=j; k=1; for(i=2;i<n;i++) { int len=k+Next[k],L=Next[i-k]; if(L<len-i) { Next[i]=L; } else { for(j=max(0,len-i);i+j<n&&s[j]==s[i+j];j++); Next[i]=j; k=i; } } Next[0]=n; } void ex_kmp(char *T,char *s) { int n=strlen(T),m=strlen(s); int i,j,k; for(j=0;j<n&&j<m&&T[j]==s[j];j++); extend[0]=j; k=0; for(i=1;i<n;i++) { int len=k+extend[k],L=Next[i-k]; if(L<len-i) { extend[i]=L; } else { for(j=max(0,len-i);j<m&&i+j<n&&s[j]==T[i+j];j++); extend[i]=j; k=i; } } } //定義母串爲s,字串爲T,s的長度爲n,T的長度爲m,求T與S的每個後綴的最長公共前綴 //設extend數組,extend[i]表示T與S[i,n-1]的最長公共前綴,i從0到n-1,若是有一個extend[i]=m,則T在S中在i位置出現。 int main() { char s[maxn],T[maxn]; cin>>T>>s; //找出T的全部後綴與s的最長公共前綴 get_Next(s); ex_kmp(T,s); for(int i=0;i<strlen(T);i++) { cout<<extend[i]<<" "; } cout<<endl; return 0; }
修改模板:spa
①配合fail數組進行去重code
int len2=len-fail[len-1]-1;若是len%len2!=0則沒必要去重,再把len賦值給len2便可。如123123123須要去重,12312312則不須要。blog
fail數組:設j=fail[i],知足s0...j=sj-i...i到si的最大的j ci
len=8 | a | a | b | a | b | a | a | b |
fail[] | -1 | 0 | -1 | 0 | -1 | 0 | 1 | 2 |
#include<bits/stdc++.h> using namespace std; const int maxn=100050; void getfail(char *p,int *fail) { int match=-1; fail[0]=-1; for(int i=1;p[i];i++) { while(match>=0&&p[match+1]!=p[i]) { match=fail[match]; } if(p[match+1]==p[i]) match++; fail[i]=match; } } int main() { char s[maxn]; int fail[maxn]; cin>>s; //對s進行去重,len2是去重後長度 getfail(s,fail); int len=strlen(s),len2; len2=len-fail[len-1]-1; if(len%len2!=0)len2=len; cout<<len2<<endl; return 0; }
②修改get_Next函數
Next[i]表示Ti...len-1與T的最長公共前綴,作了一個return max的修改
len=9 | a | a | a | b | a | a | a | a | b |
Next[] | 9 | 2 | 1 | 0 | 3 | 4 | 2 | 1 | 0 |
int get_Next(char *s) { int n=strlen(s),ans=0; int i,j,k; for(j=0;1+j<n&&s[j]==s[1+j];j++); Next[1]=j; k=1; for(i=2;i<n;i++) { int len=k+Next[k],L=Next[i-k]; if(L<len-i) { Next[i]=L; } else { for(j=max(0,len-i);i+j<n&&s[j]==s[i+j];j++); Next[i]=j; k=i; } if(Next[i]>ans) ans=Next[i]; } Next[0]=n; return ans; }
hdu4300,給加密方式,再給密文+部分或者所有明文,輸出密文+明文,將給的串所有解密or加密,而後求兩串先後綴相同部分,便可找出密文長度
我總以爲這題是在演我
#include<bits/stdc++.h> using namespace std; const int maxn=1e5+100; int Next[maxn],extend[maxn]; void get_Next(char *s) { int n=strlen(s); int i,j,k; for(j=0;1+j<n&&s[j]==s[1+j];j++); Next[1]=j; k=1; for(i=2;i<n;i++) { int len=k+Next[k],L=Next[i-k]; if(L<len-i) { Next[i]=L; } else { for(j=max(0,len-i);i+j<n&&s[j]==s[i+j];j++); Next[i]=j; k=i; } } Next[0]=n; } int ex_kmp(char *T,char *s) { int n=strlen(T),m=strlen(s),res=m; //res=0而後wa了不少發,明文可能沒有 int i,j,k; for(j=0;j<n&&j<m&&T[j]==s[j];j++); extend[0]=j; k=0; for(i=1;i<n;i++) { int len=k+extend[k],L=Next[i-k]; if(L<len-i) { extend[i]=L; } else { for(j=max(0,len-i);j<m&&i+j<n&&s[j]==T[i+j];j++); extend[i]=j; k=i; } if(extend[i]+i>=n&&i>=extend[i])return i; } return res; } int main() { int T; scanf("%d",&T); while(T--) { char s[maxn],t[maxn],ch[30]; int mp[30],lens; scanf("%s",ch); for(int i=0;i<26;i++)mp[ch[i]-'a']=i; scanf("%s",s); lens=strlen(s); for(int i=0;i<lens;i++) { t[i]=mp[s[i]-'a']+'a'; } t[lens]='\0'; get_Next(t); int place=ex_kmp(s,t);//s的全部後綴與t的最長公共前綴 for(int i=0;i<place;i++)printf("%c",s[i]); for(int i=0;i<place;i++)printf("%c",mp[s[i]-'a']+'a'); printf("\n"); } return 0; }
fzu1901,找知足S[i]=S[i+P]的全部i,卡常
#include<stdio.h> #include<iostream> #include<string.h> #include<stack> using namespace std; const int maxn=1e6+10; int Next[maxn],extend[maxn]; void get_next(char *s) { int n=strlen(s),i,j,k; for(j=0;1+j<n&&s[j]==s[1+j];j++); Next[1]=j; k=1; for(i=2;i<n;i++) { int len=k+Next[k],L=Next[i-k]; if(L<len-i)Next[i]=L; else { for(j=max(0,len-i);i+j<n&&s[j]==s[i+j];j++); Next[i]=j; k=i; } } } int a[maxn]; int main() { int T,t=1; scanf("%d",&T); while(T--) { char ch[maxn]; scanf("%s",ch); get_next(ch); int tmp=0,len=strlen(ch); for(int i=0;i<len;i++) { if(Next[i]+i==len) a[tmp++]=i; } printf("Case #%d: %d\n",t++,tmp+1); for(int i=0;i<tmp;i++) { printf("%d ",a[i]); } printf("%d\n",len); } return 0; }
...