KMP算法

KMP算法及其相关概念

KMP算法是一个字符串匹配算法,对暴力的那种一一比对的方法进行了优化,使时间复杂度大大降低。KMP算法的作用是在一个已知字符串中查找子串的位置,也叫做串的模式匹配。比如主串s=“goodgoogle”,子串t=“google”。现在我们要找到子串t 在主串s 中的位置。·
相关概念:

s[] : 模式串,较长的字符串
p[] : 模板串,简短的串
前缀:除了最后一个字符以外,该字符串的全部头部组合
后缀:除了第一个字符以外,该字符串的全部尾部组合
部分匹配表:一个字符串的前缀和后缀的最长公有元素的长度
ne[i] : 以i为结尾的部分匹配的值,ne数组即为部分匹配表。这里ne[]有两个概念,一是next[i]的值表示下标为i的字符前的字符串最长相等前后缀的长度。二是表示该处字符不匹配时应该回溯到的字符的下标。
idx : 数组的下标

前缀后缀,部分匹配表介绍

ne[] 也就是next[] ,是字符串最长想等前后缀的长度
举个例子:求字符串数组P = {abcab)的前缀

Pabcab
idx12345
ne[]00012

ne[1] = 0 -> 前缀 = 后缀 = 空集
ne[2] = 0 -> 前缀={a} 后缀 = {b} ,前缀后缀没有交集 因此ne[2] = 0
ne[3] :前缀 = { a , ab } , 后缀 = { c , bc} , ne[ 3 ] = 0;
ne[4] :前缀 = { a , ab , abc } ,后缀 = { a . ca , bca },next[ 4 ] = 1;
ne[5] :前缀 = { a , ab , abc , abca },后缀 = { b , ab , cab , bcab},next[ 5 ] = 2;

KMP算法图解

KMP算法有两个关键步骤,求ne数组,KMP匹配
求ne数组和kmp很相似,相当于自己找自己的匹配串
在这里插入图片描述

第一个长条代表主串,第二个长条代表子串 。 蓝色表示匹配部分,绿色红色代表不匹配部分。
现在发现了不匹配的地方,根据KMP的思想我们要将子串向后移动,现在解决要移动多少的问题。
之前提到的最长相等前后缀的概念有用处了。因为蓝色部分也会有最长相等前后缀。如下图:
在这里插入图片描述
灰色部分就是蓝色部分字符串的最长相等前后缀,我们子串移动的结果就是让子串的蓝色部分最长相等前缀和主串蓝色部分最长相等后缀对齐。
在这里插入图片描述
接下来的流程就是一个循环过程了。事实上,每一个字符前的字符串都有最长相等前后缀,而且最长相等前后缀的长度是我们移位的关键,所以我们单独用一个next数组存储子串的最长相等前后缀的长度。
因此next[]的含义:下标为i 的字符前的字符串最长相等前后缀的长度为j。

习题

在这里插入图片描述
在这里插入图片描述

# include <iostream>
# include <algorithm>
# include <cstring>
using namespace std;

const int N = 1e6 + 10;
char s[N] , p[N];
int ne[N];

int main(){
	int m , n;
	// 下标从1开始 方便idx计算
	cin >> m >> p + 1 >> n >> s + 1;
	
	// 求next[] , i从2开始就好 ne[1]为空集
	for (int i = 2 , j = 0; i <= m; i ++){
		// 当j==0,无路可走,或者匹配串和模板串不匹配 , while 结束
		while (j && p[i] != p[j+1]) j = ne[j];
		if (p[i] == p[j+1]) j ++;
		ne[i] = j;
	}
	
	// 匹配过程 , 和求ne基本一样
	for (int i = 1 , j = 0; i<= n; i ++){
		while (j && s[i] != p[j+1]) j = ne[j];
		if (s[i] == p[j+1]) j ++;
		if (j == m){
			j = ne[j];//匹配成功继续往下匹配
			printf("%d ", i - m);
		}
	}
	return 0;
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值