思路:kmp+next数组的应用
分析:
1 题意要求的找出满足既是字符串的s的前缀又是后缀的字串输出该字串的长度。
2 先看看next数组的含义:
1:next数组只和模式串本身有关和文本串是无关的,因为next表示的是当匹配失败后模式串要回溯到哪个位置。
2:next数组存储的数据是用来当模式串与主串不匹配的时候要模式串回退到第几个字符与主串再重新匹配,我们知道KMP算法的主串是不回朔的,当不匹配的时候我们不是退回到开始位置重新匹配,而是利用已经匹配的结果将模式串回朔到下一个位置,这个位置比开始位置更近一步;
简单的说就是next[ j ]的值保存的是当模式串中第 j 个字符与主串第 i 个字符不匹配时候,模式串中的哪个字符 重新与主串第 i 个再匹配,这样总的字符比较次数比从开始位置比较的次数就少了。
3:next[j]存储的就是模式串前j个字符里前缀和后缀最大的匹配长度;也就是有j = next[j] ; 假设有模式串“abcabx”,那么next[5] = 2就是前5个字符里前缀和后缀匹配最长的长度为2即“ab”;那么就是说如果next[len] = ans , 整个串的前缀和后缀最长匹配的长度就是ans,上面的字符串“abcabx”的最长匹配就是0。
4:在模式串与标准串进行匹配时,指向他们的指针分别为j、i;当p[j]!=s[i]时,j直接变为next[j],新的p[j]继续与s[i]比较,如果不相等继续进行此操作……那么数组next[j]同样反映了,在模式串p的第j个位置之前,p[0]~p[next[j]-1]与p[i-next[j]]~p[i-1]这两段是完全一样的。假设模式串为“abcdabx”,手动模拟即可知道。
代码:
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
#define MAXN 400010
int mark;
char pattern[MAXN];
int next[MAXN];
/*求出next数组*/
void getNext(){
int len = strlen(pattern);
next[0] = next[1] = 0;
for(int i = 1 ; i < len ; i++){
int j = next[i];
while(j && pattern[i] != pattern[j])
j = next[j];
next[i+1] = pattern[i] == pattern[j] ? j+1 : 0;
}
}
/*递归输出*/
void dfs(int len){
if(len == 0)
return;
dfs(next[len]);
if(!mark){
printf("%d" , len);
mark = 1;
}
else
printf(" %d" , len);
}
int main(){
while(scanf("%s" , pattern) != EOF){
getNext();
int len = strlen(pattern);
mark = 0;
dfs(len);
printf("\n");
}
return 0;
}