超详细理解:kmp算法next数组求解过程和回溯的含义

前言

KMP算法是用来求一个较长字符串是否包含另一个较短字符串的算法。具体算法下一篇写吧,这篇主要解释next数组的求解。

代码

代码应该都看过了,先贴在这里,其中最难理解的地方就是求next数组,以及k往前回溯,这也是写本文的目的。

int *next = new int[length];
//这里的str是被包含的较短字符串,length是这个字符串的长度。
void next(char *str, int *next, int length)
{
    next[0] = -1;
    int k = -1;
    for (int q = 1; q <= length-1; q++)
    {
        while (k > -1 && str[k + 1] != str[q])
        {
            k = next[k];//往前回溯
        }
        if (str[k + 1] == str[q])//如果相同,k++
        {
            k = k + 1;
        }
        next[q] = k;
    }
}

理解

这里是用被包含的较短字符串,自己与自己匹配,求得next数组,然后再进行算法的后续步骤。

next数组中储存的是这个字符串前缀和后缀中相同字符串的最长长度。比如abcdefgabc,前缀和后缀相同的是abc,长度是3。

next[i]储存的是string中前i+1位字符串前缀和后缀的最长长度。如abadefg,next[2]存的是aba这个字符串前缀和后缀的最长长度。

但是这里为了和代码相对应,将-1定义为相同长度为0,0定义为相同长度为1,……依次类推

这里用一个比较明显的字符串abababac来做例子,先创建一个和字符串长度相同的数组next。第一位设为-1。
超详细理解:kmp算法next数组求解过程和回溯的含义_第1张图片

所以向后移一位开始比较
超详细理解:kmp算法next数组求解过程和回溯的含义_第2张图片

a和b不同,next第二位写-1
超详细理解:kmp算法next数组求解过程和回溯的含义_第3张图片

再向后移一位
超详细理解:kmp算法next数组求解过程和回溯的含义_第4张图片

a和a相同,next数组存前一个k=-1加1等于0.
超详细理解:kmp算法next数组求解过程和回溯的含义_第5张图片

再比较下一位,相同就比前一个加一。
超详细理解:kmp算法next数组求解过程和回溯的含义_第6张图片

到第7位时,c和b不再相等,这时就用到了回溯!!!先看下一次比较时,应该移动到哪里。
超详细理解:kmp算法next数组求解过程和回溯的含义_第7张图片

原因要再回来看上一次比较,上一次比较相同长度为5。
超详细理解:kmp算法next数组求解过程和回溯的含义_第8张图片

看这5个字符串相同的前后缀的长度,即next[4]中储存的值:2再加1,因为这5个字符串就是str的前五个字符串!
超详细理解:kmp算法next数组求解过程和回溯的含义_第9张图片

所以k先回溯到2,再比较下一个字符是否相同,这里是比较c和b,不同,再回溯,这次前面剩下aba三个字符,k=next[2]=0,即前后缀还有一个字符相同,所以应该后移到下图位置。
超详细理解:kmp算法next数组求解过程和回溯的含义_第10张图片

再比较c和b,还不同,再回溯,k=next[0]=-1,然后next[7]=-1,这样就求出了next数组了。
11

我感觉看到这里,应该就真正理解了next数组求解和回溯了吧,之后的算法其实和求next数组差不多,本来想写一下,发现这篇文章写的很好,完整算法看它就好了。

你可能感兴趣的:(算法)