KMP算法是一种字符串匹配算法,它通过next数组的定义,优化了暴力匹配的时间复杂度。KMP算法的时间复杂度是O(M+N).
目录
三、算法复杂度分析
一、算法原理
1. 计算next数组
next[j]的计算方式为next[1~j]中的非平凡前缀和非平凡后缀元素一致的长度。
next数组的实现过程为:
i指针从1开始,j指针从0开始。每次索引元素时,用s[i]和s[j+1],这样做的好处是降低写代码的难度。
从第二个元素开始遍历(ne[1] = 0), 做以下操作:
(1)若不匹配,则一直循环j = ne[j];不匹配的条件是 j != 0 && s[j+1] != s[i]
(2)若匹配,则j ++; 匹配的条件是s[j+1] = s[i]
(3)执行完(1)(2)后,ne[i]即为j;
代码如下:
for(int i = 2, j = 0; i <= n; i ++ ){
//(1)不匹配
while(j && p[j + 1] != p[i]) j = ne[j];
//(2)匹配
if(p[j + 1] == p[i]) j ++ ;
//(3)记录next
ne[i] = j;
}
2. 字符匹配过程
字符匹配过程与计算next数组的过程基本一致。
实现过程为:
设置两个指针,i指向长字符串,从1开始;j指向短字符串,从0开始。
从左往右遍历一次长字符串,每次遍历时:
(1)若不匹配,则一直循环j = ne[j],不匹配的条件是j && s[i] != p[j+1]
(2)若匹配,则j ++ ; 匹配的条件是s[i] == p[j + 1]
(3)若匹配完毕,则输出,并将j = ne[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];
}
}
二、算法实现
#include <iostream>
using namespace std;
const int N = 100010;
const int M = 1000010;
char s[N], p[M];
int ne[N];
int main(){
int n,m;
//1.扫描字符串
cin >> n >> p + 1 >> m >> s + 1;
//2.记录next
for(int i = 2, j = 0; i <= n; i ++ ){
//(1)不匹配
while(j && p[j + 1] != p[i]) j = ne[j];
//(2)匹配
if(p[j + 1] == p[i]) j ++ ;
//(3)记录next
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;
}
三、算法复杂度分析
设长字符串的长度为M, 短字符串的长度为N
则计算next数组算法的时间复杂度是O(N);
字符串匹配的时间复杂度是O(M);
总时间复杂度是O(M+N)