KMP(模板)

KMP算法精讲:https://mp.weixin.qq.com/s/MoRBHbS4hQXn7LcPdmHmIg

KMP的主要思想是当出现字符串不匹配时,可以知道一部分之前已经匹配的文本内容,可以利用这些信息避免从头再去做匹配了。

前缀是指不包含最后一个字符的所有以第一个字符开头的连续子串

后缀是指不包含第一个字符的所有以最后一个字符结尾的连续子串

next数组就是前缀表

前缀表要求的就是相同前后缀的长度。

a a b a a f

a  next[0]=0

aa next[1]=1

aab next[2]=0;

aaba next[3]=1;

aabaa next[4]=2;

aabaaf next[5]=0; 

next[i]可以理解为字符串(0—i)前后缀相同的长度

求next[i]时,i指向后缀末尾字符,j指向前缀末尾字符

void getNext(int* next, const string& s) {
    int j = -1;
    next[0] = j;
    for(int i = 1; i < s.size(); i++) { // 注意i从1开始
        while (j >= 0 && s[i] != s[j + 1]) { // 前后缀不相同了
            j = next[j]; // 向前回退
        }
        if (s[i] == s[j + 1]) { // 找到相同的前后缀
            j++;
        }
        next[i] = j; // 将j(前缀的长度)赋给next[i]
    }
}

此时如果输入的模式串为aabaaf,对应的next为-1 0 -1 0 1 -1。

这里j和next[0]初始化为-1,整个next数组是以 前缀表减一之后的效果来构建的。

那么前缀表不减一来构建next数组,代码如下:

    void getNext(int* next, const string& s) {
        int j = 0;
        next[0] = 0;
        for(int i = 1; i < s.size(); i++) {
            while (j > 0 && s[i] != s[j]) { // j要保证大于0,因为下面有取j-1作为数组下标的操作
                j = next[j - 1]; // 注意这里,是要找前一位的对应的回退位置了
            }
            if (s[i] == s[j]) {
                j++;
            }
            next[i] = j;
        }
    }

此时如果输入的模式串为aabaaf,对应的next为 0 1 0 1 2 0,(其实这就是前缀表的数值了)。

那么用这样的next数组也可以用来做匹配,代码要有所改动。

实现代码如下:

class Solution {
public:
    void getNext(int* next, const string& s) {
        int j = 0;
        next[0] = 0;
        for(int i = 1; i < s.size(); i++) {
            while (j > 0 && s[i] != s[j]) {
                j = next[j - 1];
            }
            if (s[i] == s[j]) {
                j++;
            }
            next[i] = j;
        }
    }
    int strStr(string haystack, string needle) {
        if (needle.size() == 0) {
            return 0;
        }
        int next[needle.size()];
        getNext(next, needle);
        int j = 0;
        for (int i = 0; i < haystack.size(); i++) {
            while(j > 0 && haystack[i] != needle[j]) {
                j = next[j - 1];
            }
            if (haystack[i] == needle[j]) {
                j++;
            }
            if (j == needle.size() ) {
                return (i - needle.size() + 1);
            }
        }
        return -1;
    }
};

你可能感兴趣的:(算法,leetcode,数据结构)