代码随想录day9|实现strStr()、重复的子字符串

实现strStr()

一般的字符串匹配问题我们可以使用KMP算法来处理,当我们搜索文本串和模式串是否匹配的时候,我们先得到模式串的一个前缀表,其中前缀表中存放的内容是模式串的最长相等前后缀。例如文本串为:aabaabaafa,模式串为:aabaaf,那么文本串的前缀表就是010120。当我们开始搜索时,我们发现在模式串f字符不匹配,我们就f前缀表中前一个字符的前缀表中的数值,发现是2,那么我们就跳到模式串下标为2的字符,继续遍历字符串。对于aabaaf来说,在f处不匹配,就是最长相等后缀aa后面的一个字符f不匹配,那么我就可以跳到最长相等前缀aa后面的一个字符b来重新进行匹配,此时前缀表中记录的最长相等前后缀的长度就是这个字符串b的下标。我们首先需要先得到这个前缀表。

class Solution {
public:
    //得到模式串needle的前缀表
    void getNext(int* next,string& s)
    {
        int j = 0;//用j来表示最长前缀,但是同时j也表示最长前后缀的值
        next[0] = j;
        for(int i = 1;i < s.size();i++)//用i来表示最长后缀
        {
            while(j > 0 && s[i] != s[j])//前缀、后缀不相等的情况
            {
                j = next[j - 1];
            }
            if(s[i] == s[j])//前缀、后缀相等的情况
            {
                j++;
            }
            next[i] = j;//前后缀相等时,更新next[i]为j++的数值;不相等时,更新为next[i]为回退后的数组
        }
    }

    int strStr(string haystack, string needle) //haystack是文本串,needle是模式串
    {
        int next[needle.size()];//创建一个数组用来存放前缀表的内容
        getNext(next,needle);//得到前缀表
        int j = 0;
        for(int i = 0;i < haystack.size();i++)//用i来遍历文本串
        {
            while(j > 0 && haystack[i] != needle[j])
            {
                j = next[j - 1];//j回退到j-1所对应的下标处
            }
            if(haystack[i] == needle[j])
            {
                j++;
            }
            if(j == needle.size())
            {
                return (i - needle.size() + 1);
            }
        }
        return -1;
    }
};

重复的子字符

这道题的思路有两种,第一个思路就是用两个字符串s相加,结果就是s+s,当我们去掉最前面一个和最后面一个得到的字符串中能查询到字符串s,那就说明这个字符串由重复子串构成。这种思想称为移动匹配。实现这种思路我们需要调用库函数,因为库函数的内部实现原本就比较高,所以使用这种想法的时间复杂度比较高。

class Solution {
public:
    bool repeatedSubstringPattern(string s) {
        string t = s + s;
        t.erase(t.begin()); t.erase(t.end() - 1); // 掐头去尾
        if (t.find(s) != std::string::npos) return true; // r
        return false;
    }
};

 其中,对于t.find(s) != std::string::npos,npos可以表示string的结束位置,意思就是说如果在字符串t中找不到字符串s,就会返回nops。这是npos的一个用法。

这道题的另一种解法就是KMP算法。这里直接给出结论,数组长度剪去最长相等前后缀的长度就是第一个周期的长度,如果这个的长度可以被整除,那就说明整个数组是这个周期的循环。

class Solution {
public:
    //得到前缀表
    void getNext(string& s,int* 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;
        }
         
    }

    bool repeatedSubstringPattern(string s) {
        int next[s.size()];
        getNext(s,next);
        int len = s.size();
        if(next[len-1] != 0 && len % (len - (next[len - 1]))== 0)
        {
            return true;
        }
        return false;
    }
};

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值