POJ 1961 Period KMP算法之next数组的应用

题意:给一个长度为n的字符串,如果它长度为l(2 <= l <= n)的前缀部分是由一些相同的字符串相接而成,输出前缀的长度l和长度为l时字符串重复的最大次数。

例如字符串为: aaaba。对于长度为2的前缀"aa"来说, “aa”最多由两个‘a’连接而成。对于长度为3的前缀"aaa"来说,“aaa”最多由三个'a'连接而成。

思路:该问题恰好用到了next数组的特性。

在kmp算法中,当字符串匹配失败时,next数组给出模式串接下来要匹配的位置。它的目的在于尽可能得利用模式串的特征少往回退。

假如匹配失败的位置为j,则对于S[0]S[1]S[2]...S[j-1]都是匹配成功的。现如果有一个最大的k,且满足S[0]S[1]S[2]...S[k-1]与S[j-k]S[j-k+1]...S[j-1]相同,则可知接下来应当将模式串的S[k]与主串匹配,即next[j] = k。

考虑该题情况,如果长度为l的前缀是由字符串重复构成的,则next[l] != 0(由上面k的定义可知),且此时构成前缀的重复子串的最小长度为l - next[l],l % (l - next[l]) = 0,最大重复次数为l / (l - next[l])。

 

 1 #include<stdio.h>
 2 #define maxn 1000010
 3 char str[maxn];
 4 int next[maxn], len;
 5 void get_next()
 6 {
 7     next[0] = -1;
 8     int i = 0;
 9     int j = -1;
10     while (i < len)
11     {
12         if (j == -1 || str[i] == str[j])
13         {
14             i++; j++;
15             next[i] = j;
16         }
17         else j = next[j];
18     }
19 }
20 int main()
21 {
22     int cas = 1;
23     while (scanf("%d", &len) && len)
24     {
25         scanf("%s", str);
26         get_next();
27         printf("Test case #%d\n", cas++);
28         for (int i = 2; i <= len; i++)
29             if (next[i] && i % (i - next[i]) == 0)
30                 printf("%d %d\n", i, i / (i - next[i]));
31         printf("\n");
32     }
33     return 0;
34 }

 

 

 

posted @ 2013-08-06 20:21  fenshen371  阅读(222)  评论(0编辑  收藏  举报