前言
KMP算法在解决字符串匹配问题时十分重要,本文将为大家介绍KMP算法
一、如何字符串匹配?
(1) 暴力做法:该方法是我们常常想到的,虽然该方法好理解,但是该方法有较高的时间复杂度。
模板:
(2)KMP算法:
KMP算法的核心是求解next[]数组,即我们在匹配失败后j应该跳到的位置,下面给出next数组的求法 模板:
for(int i = 2,j = 0;i <= n;i ++){
while(j && p[i] != p[j+1]) j = ne[j];
if(p[i] == p[j+1]) j++;
ne[i] = j;
}//匹配自己
KMP算法的流程如下:
假设现在文本串S匹配到i位置,模式串P匹配到j位置,
如果j = -1,或者当前字符匹配成功(即S[i] == P[j]),令i++,j++,继续匹配下一个字符;
如果j != -1,且当前字符匹配失败(即S[i] != P[j]),则令i不变,j = next[j],即模式串P相对于文本串S向右移动了j - next [j]位。当匹配失败时,模式串向右移动的位数为:j - next[j],且此值大于等于1。
next数组各值的含义:代表当前字符之前的字符串中,有多大长度的相同前缀后缀。例如next [j] = k,代表j之前的字符串中有最大长度为k 的相同前缀后缀,即在某个字符失配时,该字符对应的next值会告诉下一步匹配中,模式串应该跳到哪个位置(跳到next[j]的位置)。如果next[j]等于0或-1,则跳到模式串的开头字符,若next[j] = k 且 k > 0,代表下次匹配跳到j之前的某个字符,而不是跳到开头,且具体回溯跳过了k个字符。
模板:
for(int i = 1,j=0;i <=m;i ++){
while(j && s[i] != p[j+1]) j = ne[j];
if(s[i] == p[j+1]) j++;
if(j==n)
{
//cout << i-n << " ";
//j = ne[j];
}//匹配成功
}
二、典型例题
1.例题
2.AC代码
#include<iostream>
using namespace std;
const int N = 1e5+8;
int n,m,ne[N];
string s,p;
int main()
{
cin >> n >> p >> m >> s;
p = ' '+p;
s = ' '+s;
for(int i = 2,j = 0;i <= n;i ++){
while(j && p[i] != p[j+1]) j = ne[j];
if(p[i] == p[j+1]) j++;
ne[i] = j;
}//匹配自己
for(int i = 1,j=0;i <=m;i ++){
while(j && s[i] != p[j+1]) j = ne[j];
if(s[i] == p[j+1]) j++;
if(j==n)
{
cout << i-n << " ";
j = ne[j];
}//匹配成功
}
return 0;
}