KMP算法学习笔记

KMP学习笔记

这是我学习kmp算法的个人理解

算法描述

  1. 变量说明:
  • string pat :就是要匹配得到的子串——模式串
  • string txt :就是被匹配的母串
  1. 算法目标:
    这个算法的目标是在母串中找子串
  2. 常用思路:遍历匹配
    即朴素的无回溯的模式匹配

但是遍历匹配得到的算法复杂度为n(O2),因为遍历会将小子串(肯定不是pat目标所得)反复进行比较,浪费了大量资源;于是我们对于给定的子串pat规定一种顺序,让匹配时不至于全部回退到首位,并建立一个next[]数组储存这个顺序,这样不至于完全遍历毫无意义的子串

算法思路

下面的话是我对这个算法的浅薄见解,如果不理解也不影响学习

因为text串前面已经匹配成功的子串和pat串前端是相同的,所以单独考虑par串就可以了:就是计划出来当 pat[i] 位不匹配时应该退回到哪个位置,而不用考虑test应该是什么
最终目标就是每一位 pat[i] 如果没匹配都可以找到回退几位
把匹配想像成点一串灯,只有匹配成功这个灯才亮,算法要保证灯亮的最多,即达到效率提高

从头开始,然后递归:如果不匹配,就转到上一次的处理方法。如果匹配,就到下一个状态

  • 把上一次的处理方法用x来记录
void get_next(string pat, int next[]) {
	//i表示当前正在匹配的下标
	int i = 1;
	next[1] = 0;
	//shadow表示正在匹配的上一个位置,本质上也是下标,递归使用
	int shadow = 0;
	while (i < pat.length()) {
		//当下标比pat小的时候,循环开始4
		//pat[i] == pat[shadow]表示pat【i】和匹配的上一个位置相同——在匹配过程中呈现此位的字符和模式串字符相同,匹配成功
		//这时i就跳转到下一格,同时shadow跟进跳转
		if (shadow == 0 || pat[i] == pat[shadow]) {
			++i;
			++shadow;
			next[i] = shadow;
		}
		//如果匹配不成功,shadow就在回退一个状态,回退到匹配为止
		else
		{
			shadow = next[shadow];
		}
	}
}

要是还不懂的话,推荐看知乎大神的讲解,内含大量图片,gif解释用法
他用的是dp二维数组,但是原理都是一样的,下面是他的部分代码

int main() {
	string pat;
	//pat是要匹配的子串
	string txt;
	//txt是被匹配的串
	cin >> pat;
	cin >> txt;
	int dp[100];
	//dp是状态转移的描述,下标表示所取的pat的坐标
	int x;
	//x是影子状态,就是退回的最大位数

	//此处为核心算法
	{
		//基础情况:输入的字符是首字符,状态1点亮
		dp[0][pat[0]] = 1;
		//此时影子状态为0
		x = 0;
		//影子状态就是递归,始终保持在当前状态的上一个状态
		//一旦现在状态无法跳转到下一个,就转移到上一个状态应该转移的位置
		//使用循环达成
		for (int j = 0; j < pat.length(); j++) {
			//在pat中每一个字符进行构建状态转移表格

			for (int c = 0; c <= 256; c++) {
				//对每一个ASCII码进行构建表格

				//此处递归解释在上面
				dp[j][c] = dp[x][c];
			}
			//当退出循环时,pat当前状态会前进一步
			dp[j][pat[j]] = j + 1;
			//所以影子状态也要前进一步
			x = dp[j][pat[j]];
		}
	}

	int M = pat.length();
	int N = txt.length();
	// pat 的初始态为 0
	int j = 0;
	for (int i = 0; i < N; i++) {
		// 计算 pat 的下一个状态
		j = dp[j][txt[i]];
		// 到达终止态,返回结果
		if (j == M) return i - M + 1;
	}
	// 没到达终止态,匹配失败
	return -1;
	
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值