刚刚写了点
我刚刚调试了几次 ,然后又在自行输出 。 我先说说 啊,就是这个 next 数组就为什么可以求出前后缀最长 相同的数量? 首先说说 前后缀,例如字符串 aaaa,我们就直接用眼睛看的话,就是最长就是3,aaa a ; a aaa。 这就是最长的前后缀,我们怎么用代码实现的呢? 首先 前后缀 不能是一样的 (就如这个前后缀 不能是 aaaa,aaaa 这就不是前后缀了) ,所以说,最长的肯定是 (在相同的情况下,i和这个j 数量相差1 的时候,我想这就是 i初始设置为0,j初始为-1,数量相差1,这应该就是在这种情况下最长的了 )。。。
下面 看其他的情况 ,就是 上面那种情况和这种情况也是,当 i和 j 之间相差 1时,这个就是前后缀数量最长的时候了(但不一定前后缀相同,只是在这里说一下),一开始 i=0,j=-1 ,我们就开始 以这个 最长的前后缀数量 开始 ,如果 s[i]!=s[j],我们就开始跳转了,i和j之间的距离逐渐拉大(但是也有限制的,直到 j==-1的时候,就停了) ,逐渐拉大的意思就是 从前后缀数量 最大逐渐减小,看看这时候前后缀 比较 s[i] s[j]的关系,如果还不行,我们就继续跳转,(好像跳转都会一直将j跳到 -1 去)。如果j 到了 -1,还没有,我们就只能 将 i++,j++,这个意思好像就是 中间这段我们已经没有利用价值了,再怎么减少前后缀数量,都不能形成相同前后缀了 。(所以在每次 跳转到 j==-1时 ,next[i]=j ,这个意思好像就是 这前面的这段 没有前后缀相同的,(可能前面有相同的,但是前面一直到这里是没有的),有点像DP状态转变,每个点都是一个状态点好像 )。这样就开始了新的一轮前后缀数量查,与前面一样。
对了,还得补充一点,就是上面所说的,每个点就好像是一个状态,与前面经过的点和后面的点没有什么太大的关系。所以在每次 aaa,s[i]==s[j]的时候,就都会next[i]=j; 这个 j因为做了j++ 操作 ,所以就是前后缀相同数量。 每个点 都会有一个状态。就像 aabbaa 在 ab 这里断的时候,就会j跳转到-1 处,重新来,结果发现还是 a b 矛盾,没有办法,在逐渐减到 -1,再来 ,这时 就是 a a,就这样 配下去了。更新next 数组。
所以说 ,我感觉next 奇妙之处,前后点的状态不受影响,自己有自己的状态,互不影响。
还有,一开始看不懂,就去 看 它怎么去找的前后缀 (到底是怎么去找的,就没有太注意i 和 j 之间 距离的变化,我感觉 i 和j之间 挨的越近,前后缀数量就越多(只是前后缀相同情况),一开始 从相隔1 (相对的,有的相隔不是1), 到相隔越来越大(不相同的情况)(相对的)。 )。
说了这么多,希望对你有点 帮助
我放出测试代码:
#include<iostream>
#include<cstdio>
#include<queue>
#include<algorithm>
#include<set>
#include<vector>
const int maxn=1000005;
using namespace std;
#include<map>
#include<string>
#include<string.h>
typedef long long ll;
int anext[maxn];
void getnext(string s)
{
int i=0;
int j=-1;
anext[0]=-1;
while(i<s.length())
{
if(j==-1||s[i]==s[j])
{
i++;
j++;
anext[i]=j;
cout<<"此时i "<<i-1<<"->"<<i<<" ";
cout<<"此时j "<<j-1<<"->"<<j<<" ";
cout<<"更新 next 数组"<<' ';
printf("next[ %d ]= %d",i,j);
cout<<endl;
}
else
{
cout<<"此时i为"<<i<<" "<<" 此时j为"<<j<<" ";
cout<<"开始跳转"<<" ";
cout<<j<<"->";
j=anext[j];
cout<<j<<endl;
}
}
}
int main()
{
int n;
int kase=0;
char a[maxn];
while(scanf("%s",a)!=EOF)
{
memset(anext,0,sizeof(anext));
getnext(a);
for(int i=1;i<=strlen(a);i++)
cout<<anext[i]<<' ';
cout<<endl;
}
return 0;
}
如有出入,请不吝赐教,互相学习。