kmp初步理解

KMP作为字符串搜索的关键算法,打破了BF时间复杂度O(n*m)的低效思维,利用next数组,即前缀表来减少匹配次数,从而减少运行时间,其复杂度为O(n+m)。(n是主串的长度,因为最坏情况下主串的每一个字符都被比较过,m是模式串的长度)。

我这里主要讲的是前缀表的计算方法和这种思维想法,仅个人见解。

关于前缀表的概念:

前缀表是用来回退的,它记录了模式串与主串(文本串)不匹配的时候,模式串应该从哪里开始重新匹配。

首先了解一下什么是前缀后缀

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

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

对于next数组,不同人,不同资料有不同的给法,在我目前学习的数据结构书中,给出的字符串是以下标1开始存储的,而我在网上资料以及大多接触的都是从0开始存储,因为这种存储方便输入。但二者并没有太大区别。

先讲一下从下标1开始存储的字符串

                    { 0 ,j=1 
next[ j]=        { Max { k |1<k<j && t1t2t..t k-1 = t(j-k+1) + t..+t j-1 }
                    {1 k=1
***第一次用csdn发布笔记,不会搞公式……***
我用文字对他的解释为:
next数组可以理解为一种前缀表,记录的是该字符之前(不包括该字符)的串满足最大相同前后缀的长度; 
void bookNext(int *next,const string& s){
	int i=1;next[1]=0;int j=0;
	while(i<s.length()){
		if(j==0 || s[i]==s[j]){++i;++j;next[i]=j;}
		else j=next[j];
	}
}

因此按照书上的解释,可以给出这几行代码

在next数组的存值时,可以理解为模式串与模式串的匹配,来查找最长相等前后缀,并将这个值存在next数组中,在匹配过程中出现失配也可以通过next数组回溯。

***手动分割线***

下面是以下标为0存储的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;
        }
    }

具体next数组实现。

下面给出完整的KMP代码

class Solution {public:
    void getNext(int* next, const string& s) {
        int j = 0;                            
        next[0] = 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) {  //haystack为主串 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;
    }
};

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值