KMP算法

1. 原理:“移动位数 = 已匹配的字符数 - 对应的部分匹配值”;

为了计算简明,可以将原理的跳转方法记录在next数组中(next数组以0开始还是-1开始都可以);

next[j] 的含义是:在子串的第j个字符与主串不匹配时,把子串的next[j]位置移动至与主串当前位置比较;

因此KMP算法的主要过程就在于求子串的next数组了。

 

2. nextval数组:对next数组进一步改进,如果跳转到的next[j]位置的字符与当前字符一样,那肯定还是不匹配,所以应该继续递归,也就是将next[j]修正为next[next[j]],直至与当前字符不相等,如此修改的数组记为nextval。

 

3. 匹配过程:如果next[j]==-1,则主串后移一位;否则把模式串跳到next[j]位置继续匹配。

整个过程中主串指针不回移,求next需要O(m),匹配一遍O(n),总共O(m+n)

 

4. 例题:S="ababaaababaa",计算最大匹配值next

https://www.bilibili.com/video/BV1jY4y177Ci/?spm_id_from=333.337.search-card.all.click&vd_source=120f06d629f015168f845b278f4b9f2f

next:011234223456

nextval:010104210104

 

5. 代码实现:leetcode28

class Solution {
public:
    int strStr(string haystack, string needle) {
        return kmp(haystack,needle);
    }
    int kmp(string s,string t){
        int i=0,j=0;
        int len1=s.size(),len2=t.size();
        if(len2==0)return 0;
        vector<int> next=get_nextval(t);
        while(i<len1&&j<len2){
            if(j==-1||s[i]==t[j]){//该位匹配或者需要从下一位重来
                ++i,++j;
            }else{
                j=next[j];
            }
        }
        if(j==len2)return i-len2;
        return -1;
    }
    vector<int> get_nextval(string t){
        int len=t.size();
        vector<int> nextval(len);
        nextval[0]=-1;
        int i=0,j=-1;
        while(i<len-1){
            if(j==-1||t[i]==t[j]){//匹配了,按照记录+1给next赋值
                ++i,++j;
                if(t[i]!=t[j])nextval[i]=j;
                else nextval[i]=nextval[j];
            }else{//没匹配,循环继续
                j=nextval[j];
            }
        }
        return nextval;
    }
};

 

posted @ 2021-06-13 20:55  Kinghao0319  阅读(104)  评论(0编辑  收藏  举报