小编刚学KMP算法时一脸懵逼,看了好多求next、nextval数组的方法也懵懵懂懂,小编深知看不懂代码的心情,所以当小编终于茅塞顿开之时写下这篇博客来帮助仍在水深火热中的小伙伴们。本篇博客主要对《数据结构》——严奶奶版的模式匹配算法做一些解释,也会用到书中的一些例子,能帮助到小伙伴们就最好不过了!!!
本文章不会重点介绍KMP算法,
只用容易理解的方式解释next数组和nextval的求法
首先来讲next数组干了一件什么事情,从KMP算法我们已经知道了当模式串P在j位置“失配”时,我们需要将P回溯,具体回溯到哪个位置才是最佳位置呢?根据位置的不同产生了next数组和nextval数组,那我们先来看看next数组怎么求,有了next数组的基础理解nextval数组就会容易许多了。
熟悉KMP算法的小伙伴们都知道,next数组的主要作用就是找最长相同子串并把“可能失配位置”的回溯位置存储到数组中,比如在j的位置“失配”,我们要回溯到k的位置,k应该满足什么条件呢?
如果j不等于1,那么k需要满足P1P2…Pk-2Pk-1 = Pj-k+1Pj-k+2…Pj-2Pj-1,如果j等于1那么k就只好等于0了,如果j不等于0也不满足P1P2…Pk-2Pk-1 = Pj-k+1Pj-k+2…Pj-2Pj-1,那么这个意思呢就是连P1都不等于Pj-1,那么P串只能从头开始了,也就是说j只能等于1了,说了这么一长串主要想推出以下的公式,还有点懵逼的小伙伴可以结合k的意义(最长相同子串+1)来理解了:
上述就简单回顾了一下next数组在干什么,接下来我们正式开始将如何求next数组。
比如上面这个模式串,我们要求它的next数组,根据图片以及上面给到的公式能容易得出next数组为[0,1,1,2,2,3,1,2],但是计算机又不能一眼看出来,所以我们需要找一个适合编程的算法来计算next数组,这里呢我们选用经典的递推算法,就和高中学过的数列一样,如果我们知道an和an-1的关系,那么整个数列的通项公式我们就可以算出来,区别在于现在递推公式更适合计算机思维,更适合编程表达,那么我们就来看看j和j+1的next数组值即next[j]和next[j+1]有什么关系。
- 假设next[j] = k,那么根据我们上面所提到的,就有关系式‘P1P2…Pk-2Pk-1 = Pj-k+1Pj-k+2…Pj-2Pj-1’,接下来判断next[j+1]的值
- 很自然的一个想法就是判断Pj和Pk是否相等,如果Pj = Pk,那么结合上边的式子,就会有‘P1P2…Pk-1Pk = Pj-k+1Pj-k+2…Pj-1Pj’,那么满足条件的最长相同子串的长度就是k了,所以假如在j+1的位置“失配”,应该返回到k+1的位置重新匹配,也就是说next[j+1] = k+1 = next[j]+1(递推关系)
- 如果Pj ≠ \neq = Pk,也就是说‘P1P2…Pk-1Pk ≠ \neq = Pj-k+1Pj-k+2…Pj-1Pj’,但是会不会存在某个q<k使得P1P2…Pq-2Pq-1= Pj-q+1Pj-q+2…Pj-2Pj-1呢?如果存在,q又会是多少呢?假设存在这个q,如果Pj = Pq,是不是回到第二条讨论的内容了呢?是不是next[j] = q+1呢?如果这次迭代中Pj ≠