kmp中next数组的建立
kmp算法中最难的莫过于next数组的构建,刚学的时候看了代码也和sb一样不知道咋回事,只能靠背下来,过几天又忘记😅,(确实拉胯),最近似乎理解了,记个笔记。
其实啊,next数组的构建是dp算法实现的(怎么就没人说呢,我害推了半天卧槽)。
先设要求的字符串为str,既然是dp,那么第一步:
int dp[1000] = {0,};//dp[i]指从str[0]-str[i]闭区间中的最长相等前后缀。
memset(dp,-1,sizeof(dp));
dp中最重要的就是递推公式的推导了,接下来推一下递推公式。
比如当str="abcabcg"时。
我们取两个指针,一个i先指向str[0],j指向str[1]。
第一步:很明显str[0]不等于str[1],所以我们令dp[1]=-1,然后j++,向第三个字符前进
第二步:和第一步一样依旧i,j的指向值不相等
于是j++找第四个字符
第三步:同第二步j++
第四步:我们发现i,j指向的值相同了,那么就要进行与上面稍有不同的操作了,此时的最长相等前后缀明眼人都看出来了吧,就是1,于是dp[j]=1-1,这里也i++,为下一步准备(这里可以自己写一写体会一下为什么要i++)
第五步:动态规划的特点是存储之前的状态为下面的服务,基于这个思想,我们向前寻找是否有可以利用的值。此时求的是dp[4],也就是"abcab"的最长相等前后缀,而我们的dp[3]是"abca"的最长相等前后缀,所以粗略确定与dp[3]有关,通过观察,dp[4]本应该是"ab"长度,而dp[3]已经有了"a"的长度,那么只要比较str[i]与str[j],发现相同,我们直接dp[3]+1就可以了。到现在,我们初步得出的公式有
if(str[i]==str[j]) dp[j]=dp[j-1]+1;
i++;
第六步:我们可以通过这一步验证一下刚才得到的公式,发现正确,进行与上面第五步相同的操作
第七步:我们又发现i,j指向的值又不同了,那么又有与上方不同的操作了。
此时算的是abcabcg的最长相等前后缀,一看就知道它没有,如何计算呢?
这里的计算方法要自己推一下,这里给出我的方法
计算方法:此时的i指向str[3],j指向str[7],发现不同,将i退回0,j不变,如果str[i]与str[j]还是不同,那么就说明[0,7]一个相等前后缀都没有,dp[j]赋值-1,j++;如果相同赋值0,i++,j++;
最后抽象出代码:
什么阴间代码编辑器。。。
#include<iostream>
#include<string>
#include<memory>
int main(){
int dp[1000] = {0,};
memset(dp,-1,sizeof(dp));
string str;
cin >> str;
int len = str.size();
for(int i = 0,j = 1;j < len;j++)
{ if(str[i] == str[j])
{
dp[j] = dp[j-1] + 1;
i++;
}
else
{
i = 0;
if(str[i] == str[j])
{
dp[j] = 0;
i++;
}
}
cout << dp[j]<<' ';
}
return 0;
}