题意:求字符串的最小循环节长度,一个只要求原字符串的,一个要求所有前缀串的。
考虑KMP算法中的next数组,next[i]+1表示使前缀后缀相等的最大长度,可以推知L=s.size()-next[i]-1为字符串的最小循环节长度。
当s.size()是L的整数倍时,L即是循环节长度,否则最后一个循环节不完整(如abcabca),答案只能是s.size()。
(问题:如何证明当x为最小循环节长度时,如果y不是x的倍数,循环节长度一定不能为y?)
两题都可以一遍getnext实现。O(n)
#include <iostream> #include <string> using namespace std; const int N =1E6+7; int nxt[N]; void getnxt(string s){ int k=-1; nxt[0]=-1; for(int i=1;i<s.size();i++){ while(k!=-1&&s[i]!=s[k+1])k=nxt[k]; if(s[i]==s[k+1])k++; nxt[i]=k; int re=i+1-nxt[i]-1; if((i+1)%re==0&&re!=i+1)cout<<i+1<<" "<<(i+1)/re<<endl; } } int main() { int x,cnt=0; string s; while(cin>>x){ if(!x)break; cin>>s; cout<<"Test case #"<<++cnt<<endl; getnxt(s); cout<<endl; } }
#include <iostream> #include <string> using namespace std; const int N =1E6+7; int nxt[N]; void getnxt(string s){ int k=-1; nxt[0]=-1; for(int i=1;i<s.size();i++){ while(k!=-1&&s[i]!=s[k+1])k=nxt[k]; if(s[i]==s[k+1])k++; nxt[i]=k; } } int main() { string s; while(cin>>s){ if(s[0]=='.')break; getnxt(s); int re=s.size()-nxt[s.size()-1]-1; if(s.size()%re)cout<<1<<endl; else cout<<s.size()/re<<endl; } }