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

本文介绍了如何使用KMP算法中的strStr()函数实现字符串搜索,并详细解释了前缀表的概念及其在算法中的作用,以及如何检测重复子字符串。通过计算最长公共前后缀来避免回退,提高搜索效率。
摘要由CSDN通过智能技术生成

28. 实现 strStr()*

题目

题目链接

代码

示例代码
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;
    }
};

思路

本题是KMP算法的完美练习,因此要完成本题就是要理解KMP算法。

以下思路参照文章一文章二

备注:个人认为对于代码随想录对KMP算法的讲解难以理解。

什么是前缀表

在暴力算法中,文本串和模式串的遍历指针遇到不匹配的情况都会回退,造成了不必要的时间浪费。

KMP算法借助部分匹配表(前缀表),使得文本串的遍历指针永不回退,遇到不匹配的情况只需要回退模式串的指针即可。

也就是说,前缀表的作用就是指导模式串的指针怎么回退

注意,计算前缀表只与模式串有关,与文本串没有任何关系

前缀表怎么计算

前缀表的说法并不准确,这会导致我们对其理解和计算出现偏差,前缀表的“前缀”可以理解为“最长公共前后缀”,“最长相等前后缀”。

前缀表的值与前后缀都相关。

以串“aaba”为例,他的前缀是“aab”,后缀是“aba”,此时“最长公共前后缀”为1。

以串“aabaa”为例,他的前缀是“aaba”,后缀是“abaa”,此时“最长公共前后缀”为2。

请注意观察,其计算的方法比较微妙。

而前缀表就是要给出当前串的各位的“最长公共前后缀”。以“aaba”为例,它的前缀表分别要给出“a”,“aa”,“aab”,”aaba“的“最长公共前后缀”:{0,1,0,1}。

前缀表具体计算的代码形式暂且不去理解,二刷代码随想录的时候再深究。

前缀表怎么使用

前缀表是用于指导式串的指针怎么回退的,但是并不是直接使用前缀表的值进行回退,而是需要进行一些计算。

概括地来说,计算跳过长度的公式为跳过的长度=匹配上字符串中间字符长度-前缀表值,当然,可能不是很准确,二刷代码随想录的时候再深究。

459.重复的子字符串*

题目

题目链接

代码

示例代码
class Solution {
public:
    void getNext (int* next, const string& s){
        next[0] = -1;
        int j = -1;
        for(int i = 1;i < s.size(); i++){
            while(j >= 0 && s[i] != s[j + 1]) {
                j = next[j];
            }
            if(s[i] == s[j + 1]) {
                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] != -1 && len % (len - (next[len - 1] + 1)) == 0) {
            return true;
        }
        return false;
    }
};

思路

思路基本上同上。

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值