KMP算法:
1、violentMatch()
int violentMatch(string s,string p){
int lens = s.length();
int lenp = p.length();
int i = 0,j = 0;
while(i<lens&&j<lenp){
if(s[i]==p[j]){
i++,j++;
}else{
i= i-j+1,j=0;
}
}
if(j==lenp) return i-j;
else return -1;
}
S[10]与P[6]不匹配,所以文本串回溯到S[5],模式串回溯到P[0],从而让S[5]跟P[0]匹配
而S[5]肯定跟P[0]失配。为什么呢?因为在之前第4步匹配中,我们已经得知S[5] = P[1] = B,而P[0] = A,即P[1] != P[0],故S[5]必定不等于P[0],所以回溯过去必然会导致失配。
它利用之前已经部分匹配这个有效信息,保持i 不回溯,通过修改j 的位置,让模式串尽量地移动到有效的位置。即下面的KMP算法
2、KMP:
next 数组各值的含义:代表当前字符之前的字符串中,有多大长度的相同前缀后缀。例如如果next [j] = k,代表j 之前的字符串中有最大长度为k 的相同前缀后缀。
接下来,咱们来写代码求下next 数组。
基于之前的理解,可知计算next 数组的方法可以采用递推:
举个例子,如下图,根据模式串“ABCDABD”的next 数组可知失配位置的字符D对应的next 值为2,代表字符D前有长度为2的相同前缀和后缀(这个相同的前缀后缀即为“AB”),失配后,模式串需要向右移动j - next [j] = 6 - 2 =4位。
向右移动4位后,模式串中的字符C继续跟文本串匹配。
对于P的前j+1个序列字符:
void getNext(string p){
int lenp = p.length();
next[0] = -1;
int k = -1,j=0;
while(j<lenp-1){
if(k==-1||p[k]==p[j]){
j++;
k++;
next[j] = k;
}else{
k = next[k];
}
}
}
总体代码:
#include<iostream>
using namespace std;
const int maxn = 1e5+5;
int next[maxn];
void getNext(string p){
int lenp = p.length();
next[0] = -1;
int k = -1,j=0;
while(j<lenp-1){
if(k==-1||p[k]==p[j]){
j++;
k++;
next[j] = k;
}else{
k = next[k];
}
}
}
int violentMatch(string s,string p){
int lens = s.length();
int lenp = p.length();
int i = 0,j = 0;
while(i<lens&&j<lenp){
if(s[i]==p[j]){
i++,j++;
}else{
i= i-j+1,j=0;
}
}
if(j==lenp) return i-j;
else return -1;
}
int kmp(string s,string p){
int lens = s.length();
int lenp = p.length();
int i=0,j=0;
while(i<lens && j<lenp){
if(j==-1||s[i]==p[j]){
i++,j++;
}else{
j = next[j];
}
cout<<"KMP"<<endl;
}
if(j==lenp) return i-j;
else return -1;
}
int main()
{
int ans = 0;
string s = "BBCABCDABABCDABCDABDE";
string p = "ABCDABD";
ans = violentMatch(s,p);
cout<<ans<<endl;
getNext(p);
for(int i=0;i<p.length();i++){
cout<<next[i]<<" ";
}
//ans = kmp(s,p);
cout<<ans<<endl;
return 0;
}
原文:https://www.cnblogs.com/Lemon1234/p/11656770.html