A - Period(KMP)

简介: A - Period(KMP)

题目:

对于具有N个字符的给定字符串S的每个前缀(每个字符具有介于97和126之间的ASCII代码),我们想知道该前缀是否是周期性字符串。也就是说,对于每个i(2 <= i <= N),我们想要知道最大的K> 1(如果有的话),使得长度为i的S的前缀可以写为AK,即A级联K时间,对于一些字符串A.当然,我们也想知道时期K.

输入

包含几个测试用例。每个测试用例包含两行。第一行包含N(2 <= N <= 1 000 000) - 字符串S的大小。第二行包含字符串S.输入文件以一行结束,具有

数字为零。

输出

对于每个测试用例,在一行输出“测试用例#”和连续的测试用例编号;然后,对于具有周期K> 1的长度为i的每个前缀,输出前缀大小i和由单个空格分隔的周期K;前缀大小必须按递增顺序排列。在每个测试用例后打印一个空行。

样本输入

3
AAA
12
aabaabaabaab
0

样本输出

测试案例#1
2 2
3 3

测试案例#2
2 2
6 2
9 3
12 4

解题思路:这个题主要考的是KMP中next[ ]数组的理解,next[k]指的是在k之前有一个长度为next[k]的字符串是字串的前缀。这个题的意思是找字符串前缀中循环的周期最大,也就是当循环体最小的时候,循环的周期才能最多。例如样例中 2 2指的是前缀的长度aa是2,然后循环体是a,循环的周期是2.

程序代码:

#include<stdio.h>
#include<string.h>
char s[2001000];
int n,next[2001000],t;
void get();
int main()
{
  int cas=1;
  while(scanf("%d",&n),n!=0)
  {
    int i,j,k;
    memset(s,0,sizeof(s));
    memset(next,0,sizeof(next));
    scanf("%s",s);
    printf("Test case #%d\n",cas++);
    get();
    for(k=2;k<=n;k++)
    {
      t=k-next[k];//最小的循环体
    //  printf("<<%d   %d\n",k,next[k]);
      if(t!=k&&k%t==0)//当k%t为整数时,才能求最大循环周期
        printf("%d %d\n",k,k/t);  
    }
    printf("\n");
  }
  return 0;
} 
void get()
{
  int i=1,j=0;
  next[0]=-1;
  while(i<n)
  {
    if(j==-1||s[i]==s[j])
    {
      i++;
      j++;
      next[i]=j;
    }
    else
      j=next[j];
  }
/*  for(i=0;i<=n;i++)
    printf("%d ",next[i]);
  printf("\n");*/
}


相关文章
|
算法
light oj 1255 - Substring Frequency (KMP)
输入两个字符串,计算二串在一串中出现的次数。 裸裸的KMP,参考刘汝佳《算法竞赛入门经典训练指南》 P212 或数据结构。
28 1
|
算法
poj 1961 Period(kmp最短循环节)
给定一个长度为n的字符串s,求他每个前缀的最短循环节。换句话说,对于每个i(2<=i<=n),求一个最大的整数k(如果k存在),使得s的前i个字符可以组成的前缀是某个字符串重复k次得到的。输出所有存在K的i和对应的k。
48 0
LeetCode contest 183 5376. 非递增顺序的最小子序列 Minimum Subsequence in Non-Increasing Order
LeetCode contest 183 5376. 非递增顺序的最小子序列 Minimum Subsequence in Non-Increasing Order
CF898D. Alarm Clock(贪心 双指针)
CF898D. Alarm Clock(贪心 双指针)
93 0