KMP算法--Next数组详解与优化

本篇文章直接跳过蛮力算法以及一些简单背景,着重讨论Next数组的意义以及其是如何工作的,并对如何求Next数组做详细记录。

1.背景

1.1 KMP算法的应用:KMP算法用来解决模式串匹配问题。

1.2 为什么要用KMP算法:普通的蛮力算法时间复杂度为O(n*m),而KMP为O(n+m)。

2.KMP算法思想

2.1 KMP算法的思想:(称T为目标串,P为待查找字串)

  1. 目标串T的 i 指针不必回溯!
  2. 通过对待查找字串P进行分析得出当每次字符不匹配时P串应如何移动

2.2 Next数组介绍:Next数组中存的是如果P[ j ] != T[ i ] 时,j 应该等于多少。即P串要向右移动多少位,此时 i 不变。Next[ j]代表前 j – 1 个字符的最大前缀和最大后缀相同的字符数,这样当P[ j ] != T[ i ]时,将j = Next[ j ] ,由于前缀与后缀相等,故此时前 j 个字符仍是匹配的。

2.3 代码实例:

int KMP(string a,string b){
	BuildNext(b);//用来求Next数组
	int n = a.length();
	int m = b.length();
	int i = 0,j = 0;
	while(j < m && i < n){
		if(j < 0 || a[i] == b[j])
			i++,j++;
		else j = Next[j];
	}
	return i-j;
}

3.Next数组的求法

3.1 与KMP算法本身类似的思想:将P串自己与自己匹配。

3.2 代码实例:

void BuildNext(string P){
	int m = P.length();
	int t = Next[0] = -1;
	int j = 0;
	while(j < m-1){
		if(t < 0 || P[j] == P[t]){
			j++;
			t++;
			Next[j] = t;//待优化
		}else t = Next[t];
	}
}

3.3 解析:这里用到一个小技巧,令Next[0] = -1,叫做字符通配符,即可以和所有字符匹配,这样就可以在P没有前缀和T[i]匹配时P从头开始比较。

4.优化

4.1 对Next数组进行优化:当待匹配子串中有较多相同字符时,以上方法还是会进行很多次无谓的比较,比如T : 00100010与P :00010进行匹配,当知道T中的第三位1与P中的第三位0不匹配时,上述方法会将P串向右移动一位,结果仍是不匹配,但是我们已经知道了0和1不等,这样还有必要每次都向后移一位吗?为什么不直接移动3位?

4.2 实现方法:我们在求前 i – 1 个元素前缀与后缀相等个数的时候,是不考虑第P[ i ]的,但是如果要是最大相等前缀的后一个字符和P[ i ]相等的话,不就表明即使你移动了之后,当前字符依然没变,也就依然不能匹配,所以要再接着移吗?

4.3 代码实例:

void BuildNext(string P){
	int m = P.length();
	int t = Next[0] = -1;
	int j = 0;
	while(j < m-1){
		if(t < 0 || P[j] == P[t]){
			j++;
			t++;
			Next[j] = P[j] != P[t]?t:Next[t];
		}else t = Next[t];
	}
}

5.完整代码
 

#include<iostream>
#include<cstdio>
using namespace std;
const int maxn = 1e5;
int Next[maxn];
void BuildNext(string P){
	int m = P.length();
	int t = Next[0] = -1;
	int j = 0;
	while(j < m-1){
		if(t < 0 || P[j] == P[t]){
			j++;
			t++;
			Next[j] = P[j] != P[t]?t:Next[t];
		}else t = Next[t];
	}
}
int KMP(string a,string b){
	BuildNext(b);
	int n = a.length();
	int m = b.length();
	int i = 0,j = 0;
	while(j < m && i < n){
		if(j < 0 || a[i] == b[j])
			i++,j++;
		else j = Next[j];
	}
	return i-j;
}
int main()
{
	string a,b;
	getline(cin,a);
	getline(cin,b);
	int pos;
	if(b.length() > a.length())	pos = -1;
	else pos = KMP(a,b);
	if(pos >= 0)	printf("%d\n",pos);
	else puts("NO");
} 

 

    原文作者:KMP算法
    原文地址: https://blog.csdn.net/weixin_41162823/article/details/83060304
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞