代码随想录训练营第九天| ●28. 实现 strStr()●459.重复的子字符串

今天的主要任务就是搞懂KMP算法!

28. 实现 strStr()

题目链接/文章讲解/视频讲解: 代码随想录
void getNext(int* next, const string& s) {     //构造next数组
        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;
    }

关于KMP算法,它的核心就在于next数组,当出现字符串不匹配时,可以记录一部分之前已经匹配的文本内容,利用这些信息避免从头再去做匹配。next数组记录的是当不匹配时,模式串该从哪一位来继续匹配,从而省去了从头开始匹配的麻烦。

关于如何求解next数组,这篇博客写的相当通俗易懂了,十分清晰:KMP算法的前缀next数组最通俗的解释,如果看不懂我也没辙了-CSDN博客

在求完next数组之后了,就可以遍历进行字符串匹配了。定义两个下标j指向模式串起始位置,i指向文本串起始位置。然后若两字母相等则依次向后遍历,若不相等,则需要将j指向next[j-1],再次进行比较,即将模式串的下标转到下一个匹配的位置进行匹配。若j指向了模式串的结尾,则说明文本串中存在能匹配模式串的字符串,则返回该起点位置,否则返回-1。

459.重复的子字符串

题目链接/文章讲解/视频讲解: 代码随想录
void getNext (int* next, const string& s){
        next[0] = 0;
        int j = 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;
        }
    }
    bool repeatedSubstringPattern (string s) {
        if (s.size() == 0) {
            return false;
        }
        int next[s.size()];
        getNext(next, s);
        int len = s.size();
        if (next[len - 1] != 0 && len % (len - (next[len - 1] )) == 0) {
            return true;
        }
        return false;
    }

这道题也是用了KMP的思想,首先先求出next数组。其次呢,

假设字符串s使用多个重复子串构成(这个子串是最小重复单位),重复出现的子字符串长度是x,所以s是由n * x组成。

因为字符串s的最长相同前后缀的长度一定是不包含s本身,所以 最长相同前后缀长度必然是m * x,而且 n - m = 1,(这里如果不懂,看上面的推理)

所以如果 nx % (n - m)x = 0,就可以判定有重复出现的子字符串。

通俗来说,就是如果该字符串是由重复子串构成的话,一定是由它末尾的那个重复子串(也就是最长相等前后缀不相等的那部分)重复了两次或多次才形成的,这样的话在next数组中的体现就是next[末尾字符] = 结尾重复子串的开头,如果满足这样就能由子串来形成整个字符串了。

具体推导还是看代码随想录上的文字版吧,解释的十分清晰。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值