KMP算法的关键在于获取next数组,其代码实现有两种方式,第一种是模拟手写next数组的过程,我们就称他为子串截取法;第二种是用类似于动态规划的思想来获取next数组.
一、子串截取法
该方法就是模拟手写next数组,截取待获取位置之前的前缀子串和后缀子串,找出它们最长的重叠部分.如果不明白可先去了解下手写next数组的方法.
代码如下,该代码为获取nextval数组,next数组稍作修改即可:
#include<string>
using namespace std;
void GetNextval(string& str,int* nextval)
{
nextval[0] = -1; //0,1位置固定为-1,0
nextval[1] = 0;
for(int i=2;i<str.size();i++)
{
int j=i-1; //从多的开始截取,可以略微提高效率
while(j >= 0)
{
if((j!=0 && str.substr(0,j) == str.substr(i-j,j)) || j==0) //截取长度为j的子串,j=0表示回到最前面.
{
if(str[j] == str[i]) //优化为nextval数组
nextval[i] = nextval[j];
else
nextval[i] = j;
break;
}
j--;
}
}
}
二、动态规划法
该方法利用了next[ i+1 ]的最大值为next[ j ] + 1,次大值为next[ next[ j ] ] + 1的递推关系,高效地求出next数组.
代码如下,获取的是nextval数组:
#include<string>
using namespace std;
void GetNextval(string& str,int* nextval)
{
nextval[0] = -1; //0,1位置固定为-1,0
nextval[1] = 0;
int i=2,j=nextval[1]; //求i=2的nextval,j也从nextval[1]开始
while(i<str.size())
{
if(j==-1 || str[i-1]==str[j]) //前者表示没有重叠前后缀,后者表示待比较位置相等
{
if(str[i] == str[j+1]) //优化为nextval的代码
nextval[i++] = nextval[++j]; //++j后j存的是next[i],不影响后续的推导
else
nextval[i++] = ++j;
}
else
j = nextval[j];
}
}