KMP之Seek the Name, Seek the Fame

本文介绍了一种利用KMP算法寻找字符串中既是前缀又是后缀的子串长度的方法。通过分析字符串特性,采用KMP算法高效地找出所有符合条件的子串长度,避免了暴力匹配带来的效率低下。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >





Seek the Name, Seek the Fame

 

题目描述:

The little cat is so famous, that many couples tramp over hill and dale to Byteland, and asked the little cat to give names to their newly-born babies. They seek the name, and at the same time seek the fame. In order to escape from such boring job, the innovative little cat works out an easy but fantastic algorithm: 

Step1. Connect the father's name and the mother's name, to a new string S. 
Step2. Find a proper prefix-suffix string of S (which is not only the prefix, but also the suffix of S). 

Example: Father='ala', Mother='la', we have S = 'ala'+'la' = 'alala'. Potential prefix-suffix strings of S are {'a', 'ala', 'alala'}. Given the string S, could you help the little cat to write a program to calculate the length of possible prefix-suffix strings of S? (He might thank you by giving your baby a name:) 
Input
The input contains a number of test cases. Each test case occupies a single line that contains the string S described above. 

Restrictions: Only lowercase letters may appear in the input. 1 <= Length of S <= 400000. 
Output
For each test case, output a single line with integer numbers in increasing order, denoting the possible length of the new baby's name.
Sample Input
ababcababababcabab
aaaaa
Sample Output
2 4 9 18
1 2 3 4 5
汉化:

小猫太有名了,许多夫妇都在山坡上爬坡到拜特兰,并要求小猫给新出生的婴儿命名。他们寻求名字,同时寻求名声。为了摆脱这种无聊的工作,创新的小猫制定了一个简单但奇妙的算法:


步骤1。将父亲的姓名和母亲的名字连接到一个新的字符串S.
第2步。找到一个合适的S前缀后缀字符串(不仅是前缀,也是S的后缀)。


例如:父亲='ala',母亲='la',我们有S ='ala'+'la'='alala'。 S的潜在前缀后缀字符串是{'a','ala','alala'}。给定字符串S,你能帮小猫编写一个程序来计算可能的前缀后缀字符串S的长度吗? (他可能会感谢你给宝宝一个名字:)
输入
输入包含一些测试用例。每个测试用例占用一个包含上述字符串S的行。


限制:输入中只能出现小写字母。 1 <= S <= 400000的长度。
产量
对于每个测试案例,按递增顺序输出带有整数的单行,表示新宝宝名字的可能长度。
示例输入
ababcababababcabab
AAAAA
示例输出
2 4 9 18
1 2 3 4 5

这次的心路历程顺手敲在了代码 里。想到哪敲到哪所以有点无厘头不过确实是思路。

///最暴力的方法就是开两个新的数组,分别从两个方向赋值,当a == b 时输出strlen(a)==
///可是如果要用这么暴力的方法那么KMP不就白学了嘛==
///所以要用KMP并且不那么暴力的方法
///是不是可以用KMP检测有没有一个后缀==前缀
///KMP的作用是检验重复字符串,那么就让初始字符串的长度不断增加,看能不能让正着的==后面倒数的
///也就是说KMP(f) ,输出的是第一段重复的首字符的位置,而
///我要找到最后一段重复的字符的末尾字符的位置是不是等于s的长度
///也就是说getkmp函数又又又不用动,把KMP函数和主函数改一改就行
///久违的EOF
///再再再次把GetNext搬过来
///可以把答案存在一个数组里,首先判断首项是否等于末项,if(s[0] == s[len - 1])    ans[0] = 1;
///上面这个思想不太OK,如果不写else那么变换不对称(个人理解),程序会出bug,所以那只是个特例
///不过答案当然是数组。数组的首项可以是一个一般结论。
///但是反过来可以让数组的首项ans[0]等于总长度,因为不管给的字符串是什么,总长度一定是一个解
///之后只要不断让长度变成next值,写一个循环直到next值为-1 也就是说倒着来
///输出这里要注意一下,之间用空格隔开而且最后换行,也就是说直到i减为零才换行
///输出的循环如果i = cnt那么会多出两个数据,所以先减掉2
///啊,终于做好了,先本地测试一下
///本地好像没问题
///WA了。日。
///忘记把测试改回来了。好了。AC代码如下:
#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;

int ne[400005];
int ans[400005];
char s[400005];

void GetNext(char *a)
{
     int len = strlen(a);
     int i = 0, j = -1;
     ne[0] = -1;
     while(i < len)
     {
          if(j == -1 || a[i] == a[j])
          {
               ne[++i] = ++j;
          }
          else j = ne[j];
     }
}

int main()
{
     while(scanf("%s", s) != EOF)
     {
          GetNext(s);
          int lens = strlen(s);
          int cnt = 0;
          
          while(lens != -1)
          {
               ans[cnt++] = lens;
               lens = ne[lens];
          }
          printf("%d*****\n", cnt);
          for(int i = cnt - 2; i >= 0; i--)
          {
               if(i == 0)
                    printf("%d\n", ans[i]);
               else
                    printf("%d ", ans[i]);
          }
     }
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值