第二章:KMP改良算法
第一章里面我们讲完了KMP算法的next数组实现法,回忆一下其实最重要的内容无非就是一、理解 i 指针无用回溯的意义,二、理解 j 指针的定位和模式串中每个元素重复度的关系,三、对next数组从观察到代码实现一条蛇式的理解掌握。 ps:文末有彩蛋哦。
自从BF暴力算法下岗之后呢,KMP算法就开始大行其道,当然也难怪,因为他大幅减少了算法的时间复杂度,而且还和朴素BF算法达到的效果一样,但是日子长了,这群众中难免有些不同的声音,有的人就说了,你KMP算法一直鼓吹自己不做无用功,那我今天就举个栗子给你,老子手里有一个主串S: “aaaabcde” 模式串T: “aaaaax” ,现在用KMP算法,先求出T串的next值, next[] = “012345”,战斗开始
我们可以发现,第一次比较,当 i = j = 5 时,哥俩就不相等了,然后依照KMP的说法,next[5] = 4 ,所以 j 老老实实去了4位,但大家其实可以发现,前几位都一样的情况下,j 指针一个一个前推十分的憨,颇有被KMP干掉的BF暴力算法的风范,故 ②③④⑤完全是多余步骤,别怀疑,第五步也是多余的。
那么发现了问题,KMP算法感受到了前所未有的惊慌,即将被遗忘在历史舞台的风险使他奔溃,他是决计不想蹈BF的覆辙,但这时,他生命中的贵人出现辽,这就是 nextval[ ] 数组。
nextval 说了,刚才这个例子里的问题,完全在于你现在聘用的next数组不给力,如果你在刚才例子的第二步就返回模式串的第一位,就可以进一步避免无用功,那么我们来看一看 nextval[ ] 数组和 next [ ] 数组的差别在哪里,我们先看看怎么由next 推出 nextval
像它这样碌碌无为的串,看看nextval怎么得出, 定义 nextval[1] = 0 。第二个元素 b 仔细看, 因为 next[2] = 1 ,我们就去找第一个元素, a 显然不等于b,这时,nextval[2] = next[2] = 1。第三个元素 a ,next等于几? 等于 1 ,第一个元素和第三个是相等的 ,则 nextval[3] = nextval[1] = 0。后面的如法炮制,不多说了,附上完整nextval,自己观察算了之后对比一哈,笔者感觉算了这个比较容易理解代码。
蛮简单对不对
OK,展示一哈 get_nextval 代码给大家,同时 next 数组 正式下岗
![](https://i-blog.csdnimg.cn/blog_migrate/213d669ca177c4f1c5381fbccbf58d98.png)
![](https://i-blog.csdnimg.cn/blog_migrate/63e03c873af6bbfb3198110ed4bdee1f.png)
至于KMP算法内容只要把原来的 next 改成 nextval 就好,不再赘述,KMP改良算法也就这样辣
对嘛,其实也不难,8要放弃
彩蛋呢在这里:
附上next数组和nextval数组的观察得数方法———瞪眼法
next数组瞪眼法
第一位的next值为0,第二位的next值为1,这是确定的,无论前两位相不相等,后面求解每一位的next值时,根据前一位进行比较。首先将前一位与其next值对应的内容进行比较,如果相等,则该位的next值就是前一位的next值加上1;如果不等,向前继续寻找next值对应的内容来与前一位进行比较,直到找到某个位上内容的next值对应的内容与前一位相等为止,则这个位对应的值加上1即为需求的next值;如果找到第一位都没有找到与前一位相等的内容,那么需求的位上的next值即为1。
我们来操练一个:
第一位是 : 0
第二位是 : 1
第三位开始,先看第二位的 next 是 1 ,那么第一位是 a ,我们第三位的前一位即 b 和 这个next 值指向的 a 显然不等,而且这个 a 已经是第一位了,那么我们在这个位置 1
第四位开始,先看第三位的next 是 1,而第三位和第一位相等,这时第四位的 next 值就是第三位的 next 值+1,即第四位置 2
第五位开始,先看第四位的next 是 2,找第二位,发现不等,看第二位的next,发现是1,第二位和第一位比较,还是不等,置1,ok
。。。。
剩下的自己操练一哈
给答案辽
nextval数组瞪眼法
上面详细讲了 next 数组的观察法,有了 next ,要观察nextval简直不要太简单,在第二章已经有了明确方法,这里不再赘述,而且直接读代码相信机滞的你也没问题