KMP算法
KMP算法
参考https://www.bilibili.com/video/BV1Er421K7kF/
计算前缀函数
pi_i的定义:第i个前缀的最长匹配真前后缀的长度。
int len = pi[i-1];//pi[i-1]代表第i-1位上最长相等前后缀的《长度》!
《下标》为len:落在了这些长度的下一个元素。
所以要考察:第len位字符和当前的第i位字符是否相等,而不是第(len+1)位。
for(int i=0;i<s.size();i++){
int len = pi[i-1];//前一位的前缀函数(最长相同前后缀的长度)
if(str[i]==str[len]){//如果这位也相等
pi[i]=len+1;//这意味着这一位的最长相同前后缀的长度等于前一位的长度+1。
}//相等情况
//if(str[i!=str[len]])//不等,找第二长,第三长.....第n长的前缀
//可以用while来代替。
while(len>0&&str[i]!=str[len]){
len = pi_next(i-1)=pi[len-1];//找下一长的pi(最长相等前后缀长度)。长的不行,找短一些的试试。
//一直找。。。直到len=0。(没有最长相等前后缀,即长度为零。)
}
}
问题是:找到i-1这个位置上的第二长的相等前后缀(除了橙色大括号,没有比它更长的了)
橙色=绿色(不知道多少,末尾x个)(两个橙色大括号的内容完全相同,所以末尾x个元素也相同)
橙色=蓝色(定义,要求的第二长的相等前后缀)
故:绿色=蓝色,发现:是橙色大括号的最长相等前后缀,没有比它更长的了,若有,要求的就不是第二长的相等前后缀了。
求橙色括号的最长相等前后缀,如何求?括号部分的就是0-len-1,之前定义过的:pi[len-1]。
所以:pi_next[i-1](下一长的第i-1这个位置上的最长公共前后缀长度)=pi[len-1];
求前缀函数:
vector<int> calc_pi(string s){
vector<int> pi;
pi[0]=0;
for(int i=1;i<s.size();i++){
int len=pi[i-1];
while(len>0&&s[len]!=s[i]){
len=pi[len-1];
}
if(s[len]==s[i])
pi[i]=len+1;
}
return pi;
}
求出了前缀函数,接下来就要进行匹配。
匹配
此时有两种方法。
1.即为传统的:求子串的前缀函数,放入主串中匹配。
2.是上述视频中提出的,将子串和主串拼接在一起,中间用一个子串,主串中都不会出现的字符来隔开,求这个新串的前缀函数,如果在字符后找到了pi(i)=子串长度的i,则说明找到了匹配串,再减去偏移量,就得到了匹配子串的首地址。
先实现1:
int findstr(string main,string pattern,vector<int> pi){
int index=0;//子串开始
for(int i=0;i<main.size();i++){
while(index>0&&main[i]!=pattern[index]){//在非开头位置失配
index=pi[index-1];//回想三个区间,找到第二长的前缀
}
if(main[i]==pattern[index]){//匹配,与上面求pi不同
index++;
if(index==pattern.size()){
return i-pattern.size()+1;
}
}
}
return -1;//没有在里面return,只能是没找到。
}
实现2:(从头到尾)
int findstr(string main,string pattern){
string s = pattern+'#'+main;
vector<int> pi(s.size());
pi[0]=0;
for(int i=1;i<s.size();i++){
int len =pi[i-1];//pi的定义是长度!下标=长度-1,所以s[len]是长度为len的子串的下一个元素
while(len>0&&s[len]!=s[i]){//失配
len=pi[len-1];//三个区间,找到第二长的前缀长度。
}
//这里的顺序不能颠倒,一定是先处理失配情况,再处理匹配情况。
//如果先处理了匹配情况,未匹配,失配后修改了len,就有可能匹配却未处理。
if(s[len]==s[i]){//匹配
pi[i]=len+1;
}
}
for(int i=0;i<pi.size();i++){
if(pi[i]==pattern.size()){
return i-2*pattern.size();//一个是新串中插入了pattern,一个是因为找到的地方在pattern的末尾。
}
}
return -1;
}

浙公网安备 33010602011771号