E - Period(KMP中next数组的运用)
一个带有 n 个字符的字符串 s ,要求找出 s 的前缀中具有循环结构的字符子串,也就是要输出具有循环结构的前缀的最后一个数下标与其对应最大循环次数。(次数要求至少为2)
InputThe input file consists of several test cases. Each test case consists of two lines. The first one contains N (2 <= N <= 1 000 000) – the size of the string S. The second line contains the string S. The input file ends with a line, having the number zero on it.
OutputFor each test case, output “Test case #” and the consecutive test case number on a single line; then, for each prefix with length i that has a period K > 1, output the prefix size i and the period K separated by a single space; the prefix sizes must be in increasing order. Print a blank line after each test case.
Sample Input
3 aaa 12 aabaabaabaab 0
Sample Output
Test case #1 2 2 3 3 Test case #2 2 2 6 2 9 3 12 4
思路: 因为next记录的是原字符串当前前缀的后缀的最大匹配长度,反过来就是当前前缀的前缀匹配长度(即可能存在的循环节长度)。
故利用好next数组能很快的解决这道题
第一步:用kmp算法,求出所有前缀(满足是两个或两个以上的循环节组成的字符串)
并用next数组保存的是当前字符串中能够匹配的最长前后缀的长度。
i-next[i]就是循环节长度.
第二步:当next数组满足i%(i-next[i])==0。且next[i]!=0。说明当前字符串中前缀为周期串,且循环次数为i/(i-next[i]);
字符串长度 1 2 3
字符串 a a a
next数组 0 1 2
l=i-(next[i]) 1 1 1 循环节长度
i%l 0 0 0 判断是否能构成循环
i/l 循环次数 不存在 2 3
我们以 aabaabaabaab 为例。
#include <stdio.h> #include <string.h> #include <algorithm> using namespace std; int Next[1100000] ; char str[1100000] ; void getnext(int len) { int i=0,j=-1; Next[0]=-1; while(i<len) { if(j==-1||str[i]==str[j]) { i++; j++; Next[i]=j; if(Next[i]&&i%(i-Next[i])==0) printf("%d %d\n",i,i/(i-Next[i])); } else j=Next[j]; } } int main() { int n,Case=1; while(scanf("%d",&n)&&n) { scanf("%s",str); next[0]=next[1]=0; printf("Test case #%d\n",Case++); getnext(n); printf("\n"); } return 0; }