KMP算法详解

在网络上看了很多优秀的博客和百科,KMP算法往往比较难理解。它是一种字符串匹配非常高效的算法,时间复杂度由O(n*m)变为O(n+m)。接下来我尝试着用简单的语言描述我对KMP算法的理解以及next和nextval的求法。


首先先来介绍一下next,next其实是一个数组,用来存储对应位置子串需要后移的位数。

例如 abdadabd,在这个子串中需要去计算它的每一位的next值。

每个位置的next值如图,那么是如何求得的呢?

首先我们要先来了解一下前缀和后缀的概念,前缀指的是包括首字符且不包括最后一个字符的所有子串,后缀指的是包括最后一个字符且不包括首字符的所有子串

例如"girfriend"这一串字符串,

其前缀指的是

{g,gi,gir,girf,girfr,girfri,girfrie,girfrien}中的元素,

而后缀指的是

{d,nd,end,iend,riend,friend,rfriend,irfriend}中的元素。

在明白前缀和后缀的概念之后,next的值其实就是前缀和后缀集合中最长相同元素子串的字符数。

在上例"abdadabd"中,

'ab'前缀为{a},后缀为{b},其没有相同元素,故next[1]= 0(下标从0开始),

'abd'前缀为{a,ab},后缀为{d,bd},其没有相同元素,故next[2] = 0,

'abda'前缀为{a,ab,abd},后缀为{a,da,bda},有相同元素a,字符数为1,所以next[3] = 0,

后以此类推,直到最后一位

'abdadabd'前缀为{a,ab,abd,abda,abdad,abdada,abdadab},后缀为{d,bd,abd,dabd,adabd,dadabd,bdadabd},可以看出其最长相同元素为'abd',字符数为3,所以next[7] = 3.


计算完next值后,我们根据公式进行子串匹配

移动位数 = 已匹配的字符数 - 对应的next值

首先逐位进行比较

找到不同之后根据公式后移3位(3-0 = 3);

发现依然不匹配,且首字符不匹配,则继续后移1位

同理继续后移一位

发现找到子串。


看到这里,应该对KMP算法的理解更深了。接下来提出一个问题,假设子串为aaaaabbbd呢?next的值应是012340000,假设主串为aaadvdfsdfsdfsdf

子串需要后移1位

在这里我们可以发现浪费了时间进行了没必要的后移,实际上第一次比较时第四位不匹配而前三位是相同字符,后移时可以将子串直接进行后移3位

由此我们得到next优化后nextval的求法

1.第一位的nextval值必定为0,第二位如果于第一位相同则为0,如果不同则为1。

2.第三位的next值为2,那么将第三位和第二位进行比较,均为a,相同,则继续将第二位与第一位进行比较,相同则为0。

3.第四位的next值为3,那么将第四位和第三位进行比较,相同,那么将第三位和第二位进行比较,均为a,相同,则继续将第二位与第一位进行比较,相同则为0。

以此类推。

相同情况时时将该位与该位对应的next值的位数进行比较,直到比较到第一位或不同,不同则值为该位next值,比较到第一位相同为0,不同为1。

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值