记录理解KMP算法(Next数组)的实践过程

还是因为考研需要,所以来学习KMP算法。

简单介绍

首先KMP算法是与暴力搜索算法相对应的,我想能看到这里来的,也不需要我多做介绍了。这里只说两点:

  • KMP算法主串指针不回溯
  • KMP最难理解的是Next数组

这里主要记录对于Next数组的理解,以及其代码逻辑的实现逻辑。

这里一些个人学习KMP的经验:

  • 别着急,慢慢看,
  • 在看别人的博客或者记录的时候,一定要搞定每个符号表达的意思

如果对于KMP不够了解的朋友,可以看一下以下,这个视频:

  • 「天勤公开课」KMP算法易懂版

对Next存在疑问的也可以看一下以下各位大佬的博客,我就是参考了很多的,才看懂的:

  • 很详尽KMP算法(厉害) -July
  • 字符串匹配的KMP算法 - 阮一峰的网络日志
  • KMP字符串匹配算法2 - 正月点灯笼

如果可以看懂上面几个博客(第三个是视频),不必看我写的了,我也是用自己的方式总结一下,加深印象。

Next数组

这里或许也可以称最大长度表,都是可以相互转换的。这里还有一个前后缀的概念,不了解的同学,也可以在上面那个视频的看一下。

这里默认大家是了解Next数组的作用,以及Next数组的是“根据最长相同前后缀确定”的这一概念,这里主要讲Next数组的代码逻辑

先行定义

  • p 表示模板串 char 数组
  • next int 数组
  • K Next数组对应的值(K)

代码推理

1.首先需要明白的第一个点,就是求Next数组是一种递推形式

即是从第 j 个推导第 j+1 个的值,所以我想大家在看过许多资料里,都说强调next[0] = 0,这样的话,就方便去推导第 1、2、3 …;

2.搞清楚Next数组对应的值(K)的含义

每个Next数组,比如Next[3] = 2,即表示的是 前三个字符模板字符串长度为3 的子串, 其最长相同前后缀长度为 2

即 Next [j] = k 表示 前 j 个字符 即模板字符串长度为j的子串 ,其 最长相同前后缀长度为 k(后面要用到)

3.已知next[j]求next[j+1]

3.1 P[k] = P[j] (k,j,均见下表)

模式串 A B C D A B C E
前后缀相同长度 0 0 0 0 1 2 3 0
Next值 0 1 1 1 1 2 3 ?
索引 P[0] P[k-1] P[k] P[k+1] P[j-k] P[j-1] P[j] P[j+1]
  • 首先我们来看这样一个表,即从Pj 推导 Pj+1

  • 即已知 P[k] = P[j] ,那么则有 Next [j+1] = Next [j] + 1 = k +1

    • 首先这样去理解,通过上表,我们可以观察到 已经有 ABC (后面的) 与 ABC(前面的) 相同了,而对于Next [j+1]来说,它的 最长相同公共前缀长度 是比Next [j] 多一个的!
    • 因为之前说过了 “Next [j] = k 表示 前 j 个字符 即模板字符串长度为j的子串 ,其 最长相同前后缀长度为 k”,
    • 现在对于P[j] 来说 其Next值,为 2,即表示,在它之前的 模板串子串的 最长公共前后缀长度为2,
    • 而又在 P[k] = P[j] 的条件下,也就是说 从 目前整个ABCDABC来看,其最长公共前后缀为3 ,
    • 而其恰好为 next[j+1] 即 j+1 之前的子串 的最长公共前后缀长度
    • 故有 Next [j+1] = Next [j] + 1 = k +1

3.2 P[k] != P[j] (k,j,均见下表)

模式串 A B C D A B D E
前后缀相同长度 0 0 0 0 1 2 0 0
next值 0 0 0 0 0 1 2
索引 P[0] P[k-1] P[k] P[k+1] P[j-k] P[j-1] P[j] P[j+1]
  • 在这个情况下,我们就不能 直接使用 Next [j+1] = Next [j] + 1 = k +1
  • 退而求其次,我们只能求更短的,即从P[0] - P[k] 之间找一个 D ,而 这里 我们通过迭代 k = next[k] 来进行查询之前 是否有 P[k’] = P[j]
    • 如果这里 在 迭代 过程中 有 P[k’] = P[j] 则 令 next[j+1] = next[k’] +1 = k’ +1
    • 如果这里 找不到 D , 即 无P[k’] = P[j] ,则 最终 P[j+1] = p[0] = 0
    • 这里说一下 ,为什么 使用 k = next [k]:
      • 首先当 P[k] != P[j] 时,可以看成模式串与自己本身在第k位发生失配 ,而在第k位失配 ,即查next[k],作为新的k,使得 P[k] 继续 和 P[j]进行判等 ,即P[next[k]] == P[j]
      • 而这样迭代下去的结果有两种
        • 找到了P[k’] = P[j] 则 令 next[j+1] = next[k’] +1 = k’ +1
        • 找不到 ,即 最终跳到 next[1] =0 即 next[j+1] = next[1] =0

代码

void getNextArray(char * s,int next[]) {
	int k = 1,j = 0, len = strlen(s);
	next[1] = 0;
	while (k<len)
	{
		if (j == 0||s[k]==s[j])
		{
			++k;
			++j;
			next[k] = j;
		}
		else
		{
			j = next[j];
		}
	}
}

总结

  • 看算法,不能着急。欲速则不达。

  • 别想着马马虎虎糊弄过去。01一点都不马虎。

  • 深知学疏才浅,如有疏忽,还望海涵,并求大佬多有指点

你可能感兴趣的:(数据结构,算法,C:从入门到放弃,算法,字符串,编程语言,c语言,kmp,字符串,匹配算法)