KMP用于判断模式串sub_str与目标串str的匹配。
简单来说可以分为两步,首先得到sub_str的next数组(数组大小与sub_str相同)。第二步利用next数组进行匹配。
难度在于理解next数组每个数代表什么以及根据sub_str求解next数组。
那next数组内的每一个数表示什么意思呢?
答:每个数next[i]表示 从sub_str[0]到sub_str[i]的子串的最长相等前后缀的长度。
前缀是指不包含最后一个字符的所有以第一个字符开头的连续子串。
后缀是指不包含第一个字符的所有以最后一个字符结尾的连续子串。
用一个例子解释如何得到子串的所有前缀、后缀,并根据前缀集合和后缀集合得到最长相等前后缀的长度:
假设sub_str为iioiikiio。
next[0]: 0-0
其对应的子串为i,根据前缀和后缀的定义,前缀集合为空集合,后缀集合为空集合。
因此最长相等前后缀的长度为0,也意味着next[0]为0。
next[4]:0-4
其对应的子串为iioii,根据前缀和后缀的定义,前缀集合为[i,ii,iio,iioi],后缀集合为[ioii,oii,ii,i]。
可以看到前缀集合和后缀集合的最长相同元素为ii,因此最长相等前后缀的长度为2,也意味着next[i]为2。
根据上面的思路,最终可以得到next数组。
代码求解:
#include<iostream>
#include<string>
#include<algorithm>
using namespace std;
int main(){
string s;
cin>> s;
int next[s.size()];
int j =0;
next[0] =0; #初始化next数组
for(int i=1;i<s.size();i++){
while(s[i]!=s[j]&&j>0){
j = next[j-1]; //j指向与当前字符比较的字符下标
}
if(s[i]==s[j]){
j++;
}
next[i] =j; //后面四行代码表示,从while循环出来之后,j只有两种情况,要么找到了s[i]==s[j]且就j!=0,要么j==0。前一种情况表示当前next[i] = j +1。后一种next[i]=0,表示下一次需要从头比较。
}
}