代码随想录第八天|字符串-KMP

KMP

28.找出字符串中第一个匹配项的下标

在这里插入图片描述
haystack称为文本串,needle称为模式串
构建next数组的操作
在这里插入图片描述
对于例子在这里插入图片描述
当出现字符串不匹配时,可以知道一部分之前已经匹配的文本内容,可以利用这些信息避免从头再去做匹配了。
通过next数组(前缀表)我们可以发现,当模式串里的f和文本串的b不相同时,应该将模式串中的指针j回退到索引为2,即j=next[j-1]
可以看到前缀表中表示以当前字符为结尾的串的相同前缀和后缀长度,如next[1],表示aa这个串的最长相同前缀和后缀的长度为1:就是a.
那么当f不匹配(s[i]!=t[j])的时候,我们已知之前一定是都和文本串匹配上了,才会来到这一步的判定,所以我们只需要获取next[j-1],就可以省略掉模式串里前缀的匹配(因为当前的文本串里的后缀已经和模式串前缀相同了,图中就是,因为next[j-1]=2,所以aa已经匹配过了,只需要比较模式串里的’b‘和文本串里的’b’即可。

对于生成next数组,是在模式串本身的基础上生成的,i指针表示后缀的末尾单词,j指针表示前缀的末尾单词

后面则是进行文本串和模式串的匹配,其基本原理都是:
在当前字符不相同的时候,则因为之前匹配文本串的后缀和模式串中的前缀相同,所以可以省略这部分的判断,继续判断下一个字符,而使用while进行j的回退则是因为,可能前缀和后缀是相同了,但是下一个字符开始就不相同了,所以继续j回退到一个新的前缀和后缀相同的状态,再看两个串的下一个字符是否相同。

class Solution {
public:
    void getNext(int* next,string& s){
        int j = 0;
        next[0] = j;
        // i遍历后缀末尾位置
        // j指向前缀末尾位置
        for(int i = 1; i < s.size(); i++){
            // 如果下一个字母和当前i指向的不相同,那么就让j回到之前前缀和
            // 后缀已经匹配的位置,然后进行下一次比较
            while(j > 0 && s[i] != s[j]){
                j = next[j - 1];
            }
            // 如果下一个字符和i对上了,代表前缀后缀匹配的长度增加了
            if(s[i] == s[j]) j++;
            // 在当前位置i,如果i+1的字符没匹配上,则可以回退到next[i],代表在i位置已经匹配上的前缀或后缀长度
            next[i] = j;
        }
    }
    int strStr(string haystack, string needle) {
        string s = haystack;
        string t = needle;
        if(t.size() == 0) return 0;
        vector<int> next(needle.size());
        getNext(&next[0], t);
        int j = 0;
        for(int i = 0; i<s.size(); i++){
            while(j > 0 && s[i] != t[j]){
                j = next[j - 1];
            }
            if(s[i] == t[j]) j++;
            if(j == t.size()) return i -(t.size() - 1);
        }
        return -1;
    }
};

459.重复的子字符串

后面的扩展题就没写了,因为很难,等二刷再补

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值