文章目录
前言
在学习kmp算法之前 我们需要知道 kmp 算法是用来干什么用的
KMP算法是一种字符串匹配算法,可以在
O(n+m)
的时间复杂度内实现两个字符串的匹配
。
所谓字符串匹配,是这样一种问题:“字符串 P 是否为字符串 S 的子串?如果是,它出现在 S 的哪些位置?” 其中 S 称为主串;P称为模式串。
#include<iostream>
#include <vector>
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6 +10;
int ne[N];
char p[N],s[N];
int n,m;
void Get_ne()
{
for(int i = 2 , j = 0 ; i <= n ; i ++)
{
while(j && p[i] != p[j + 1])(1)
j= ne[j];
if(p[i] == p[j + 1])
j ++;
ne[i] = j;
}
}
void KMP()
{
for(int i = 1 , j = 0 ; i <= m ; i ++)
{
while(j && s[i] != p[j + 1])(2)(3)
j= ne[j];
if(s[i] == p[j + 1])
j ++;
if(j == n)//匹配
{
printf("%d ",i - n);
j = ne[j];
}
}
}
int main()
{
cin >> n >> (p + 1) >> m >> (s + 1);
Get_ne();
KMP();
return 0;
}
cin>> (s + 1) >> (p + 1);
int m = strlen(s + 1);
int n = strlen(p + 1);
for(int i = 1; i <= n ; i ++)
cout<< ne[i] <<' ';
return 0;
}
(1)注意读入时是 s + 1 、p + 1(下标从 1
开始)
(2)使用while
循环来迭代(可能会持续性后退)
(3)如果j不是队首 && 上下不匹配的时候
Ps:
- 最大匹配就是最小移动 防止遗漏情况
- for循环条件 i 分别是
2 、 1
next数组
是对于模式串P而言的
具体理解
next 数组的理解
next[i] = j;
含义
1. 在 p 与 p, s 与 p 匹配的过程中,next[i] = j 的含义就是 j 指向第一个不匹配的字符,而将之前相同的前缀跳过
2. 意思是 p[1,j] == p[i - j + 1 , i] 这两个区间内的字符串相等**(i 在主串,j 在子串) 也就是**前缀 == 后缀
eg:
此时next[5] = 2;
当 j = next[5] = 2后 我们可以看到如下情况
之前的公共部分已经直接匹配