KMP算法学习记录

KMP算法学习记录
参考:
https://blog.csdn.net/qq_62982856/article/details/128003067
https://blog.csdn.net/raelum/article/details/128823560
https://www.zhihu.com/question/21923021/answer/281346746
https://blog.csdn.net/qq_37969433/article/details/82947411

一、字符串基础

1️⃣ 字符串的前缀是指不包含最后一个字符的所有以第一个字符(索引为0)开头的连续子串

比如字符串 “ABABA” 的前缀有:A,AB,ABA,ABAB

2️⃣ 字符串的后缀是指不包含第一个字符的所有以最后一个字符结尾的连续子串

比如字符串 “ABABA” 的后缀有:BABA,ABA,BA,A

3️⃣ 公共前后缀:一个字符串的所有前缀连续子串所有后缀连续子串中相等的子串

比如字符串 “ABABA”

  • 前缀有:A,AB,ABA,ABAB
  • 后缀有:BABA,ABA,BA,A

因此公共前后缀有:A ,ABA

4️⃣ 最长公共前后缀:所有公共前后缀的长度最长的 那个子串

比如字符串 “ABABA” ,公共前后缀有:A ,ABA

由于 ABA 是 三个字符长度,A 是一个字符长度,那么最长公共前后缀就是 ABA

原文链接:https://blog.csdn.net/qq_62982856/article/details/128003067

二、KMP算法

构造 next 数组,保持原串的 i 指针不动,然后将匹配串的 j 指针指向模式字符串的 next[j] 位即可。

1. next 数组构建思想

next数组由 部分匹配表(Partial Match Table) 得到

我觉得理解KMP的最大障碍就是很多人在看了很多关于KMP的文章之后,仍然搞不懂PMT中的值代表了什么意思。这里我们抛开所有的枝枝蔓蔓,先来解释一下这个数据到底是什么。

对于字符串“abababca”,它的PMT如下表所示:就像例子中所示的,如果待匹配的模式字符串有8个字符,那么PMT就会有8个值。

PMT中的值是字符串的前缀集合与后缀集合的交集中最长元素的长度。

例如,对于”aba”,它的前缀集合为{”a”, ”ab”},后缀集合为{”ba”,”a”}。两个集合的交集为{”a”},那么长度最长的元素就是字符串”a”了,长度为1,所以对于”aba”而言,它在PMT表中对应的值就是1

再比如,对于字符串”ababa”,它的前缀集合为{”a”, ”ab”,”aba”, ”abab”},它的后缀集合为{”baba”, ”aba”, ”ba”, ”a”}, 两个集合的交集为{”a”,”aba”},其中最长的元素为”aba”,长度为3。

如图所示,要在主字符串"ababababca"中查找模式字符串"abababca"。如果在 j 处字符不匹配,那么主字符串中 i 指针之前的 PMT[j −1] 位就一定与模式字符串的第 0 位至第 PMT[j−1] 位是相同的。这是因为主字符串在 i 位失配,也就意味着主字符串从 i−j 到 i 这一段是与模式字符串的 0 到 j 这一段是完全相同的

模式字符串从 0 到 j−1 ,在这个例子中就是”ababab”,其前缀集合与后缀集合的交集的最长元素为”abab”, 长度为4。所以就可以断言,主字符串中i指针之前的 4 位一定与模式字符串的第0位至第 4 位是相同的,即长度为 4 的后缀与前缀相同。这样一来,我们就可以将这些字符段的比较省略掉。具体的做法是,保持i指针不动,然后将j指针指向模式字符串的PMT[j −1]位即可
在这里插入图片描述
以图中的例子来说,在 i 处失配,那么主字符串和模式字符串的前边6位就是相同的。又因为模式字符串的前6位,它的前4位前缀和后4位后缀是相同的,所以我们推知主字符串i之前的4位和模式字符串开头的4位是相同的。就是图中的灰色部分。那这部分就不用再比较了。

为了编程的方便, 我们不直接使用PMT数组,而是将PMT数组向后偏移一位。我们把新得到的这个数组称为next数组

原文链接:https://www.zhihu.com/question/21923021/answer/281346746

2. next 数组的构建

假设有匹配串 aaabbab,我们来看看对应的 next 是如何被构建出来的。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述在这里插入图片描述
最后,往原串和匹配串头部追加一个空格(哨兵)。目的是让 j 下标从 0 开始,省去 j 从 -1 开始的麻烦。第0位的值,我们将其设成了-1。
原文链接:https://leetcode.cn/problems/find-the-index-of-the-first-occurrence-in-a-string/solutions/575568/shua-chuan-lc-shuang-bai-po-su-jie-fa-km-tb86

举例

在这里插入图片描述

三、代码

求next数组值的程序如下所示:

void getNext(char * p, int * next)
{
	next[0] = -1;
	int i = 0, j = -1;

	while (i < (int)strlen(p))
	{
		if (j == -1 || p[i] == p[j])
		{
			++i;
			++j;
			next[i] = j;
		}	
		else
			j = next[j];
	}
}

具体KMP代码如下(示例):

nt KMP(char * t, char * p) 
{
	int i = 0; 
	int j = 0;

	while (i < (int)strlen(t) && j < (int)strlen(p))
	{
		if (j == -1 || t[i] == p[j]) 
		{
			i++;
           	j++;
		}
	 	else 
           	j = next[j];
    	}

    if (j == strlen(p))
       return i - j;
    else 
       return -1;
}

原文链接:https://www.zhihu.com/question/21923021/answer/281346746

  • 17
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
个人觉得是我见过的最简单易懂的算法入门书籍。 以前搜刮过几本算法竞赛书,但是难度终归太大【好吧,其实是自己太懒了】。 略翻过教材,大多数水校的教材,大家懂的。好一点的也是那本国内的经典,不是说它写的不好,只是没有这一本好。 本书Java实现,配有大量的图解,没有一句难懂的话,而且全都是模块化实现。 讲的都是实用算法,没有那些高大上听着名字就让人感到很害怕的东西,个人觉得比CLRS实用性要强,更加适合入门的学习。 大一,推荐这本书入门 【有C语言基础即可,自己去搜索下如何用Java写出Hello World就没有问题】 大二,推荐这本书从头到尾好好读一遍,做下上千道的课后习题 【后面的有点小难度,但是难度不大值得一做,听起来很多的样子,用心去做,相信很快就可以做完的】。 大三,推荐这本书,重新温习已知算法,为找工作,考研做准备。 【可以试着自己在纸上全部实现一遍】 大四,依旧推荐这本书,没事重温经典,当手册来查也不错。 Sedgwick 红黑树的发现者,Donald E.Knuth 的得意门生,对各种算法都有比较深入的研究,他的书,我想不会太差。 也许对于数据结构的学习涉及的内容比较少,没有动态规划,图论也只是讲了很基础的东西,字符串中KMP弄的过于复杂(对比于acm)。但是瑕不掩瑜,对于绝大部分内容真的讲的超级清楚,完美的图解,就像单步调试一样,也许是一本不需要智商就能看懂的算法书(习题应该略有难度,还没有做,打算上Princeton的公开课时同步跟进)。至少这是一本让我这个算法渣渣看了爱不释手,怦然心动的书。 完美学习资源: 官方主页:http://algs4.cs.princeton.edu/home/ Coursera公开课:https://www.coursera.org/course/algs4partI (听说已经开课两期了,最近即将开课的时间是2014/09/05号那期,希望有兴趣的同学一起来学习)。 MOOC平台(笔记、讨论等): http://mooc.guokr.com/course/404/Algorithms--Part-I/ http://mooc.guokr.com/course/403/Algorithms--Part-II/ 不得不吐槽,他的lecture比他的书好,他本人讲的课更是一绝。 互补课程: 斯福坦的Algorithms: Design and Analysis, http://mooc.guokr.com/course/157/Algorithms--Design-and-Analysis--Part-1/ 快毕业了才接触到豆瓣和MOOC,看到很多经典的书籍都是推荐大学一二年级的学生看,每每想到自己却连书皮都没有摸过,就深感惭愧。 我们都老的太快,却聪明得太迟。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大田斗小木子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值