【代码随想录】刷题Day9 --- 我有自信讲清楚KMP的next原理

字符串 --- 找子串匹配算法_哈里沃克的博客-CSDN博客https://blog.csdn.net/m0_63488627/article/details/130197908?spm=1001.2014.3001.5501

 首先具体KMP算法理论在上面的博客中,不过该博客我当初写的时候并没有了解next数组实现的过程是那样的,所以只介绍了KMP的理论,next理论没有细致的给出

1.实现strStr()

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

这里我将解释我自己对于next数组的理解

先定个规矩,next[0]为-1

1.因为0位置不需要判断它跟谁一样,其实是一个能表示为初始位置的值就行。

2.但是我们不满足于表示为初始位置,因为我们查下标还要用到,所以可选-1,0这些值。

3.而之所以要选-1,因为我们把一个位置对应的相同前缀串情况,存到后一个位置去了。next有很多实现方式,但是我要实现的是开头为-1。

4.后面一个的next值表示前面的相同前缀串情况。(后续解决) 正因为如此,-1表示前面是空白

再定个规矩,next[1]为0

1.因为1位置起才开始算,1位置前面只有一个符号

2.上面也讲了后面一个的next值表示前面的相同前缀串情况。所以1位置前面就一个数,0位置的字符自己跟自己不用比,因此直接记为0

next数组后一个其实是用来存储某个位置的结果

1.简单说,这个位置的next数值代表前几个数据是对上的(看图很清楚)

此时,应该很清楚,某位置反映前面的相同前缀长了吧!!!

而且更重要的一点是,对上前缀的结果位置的next正好是开头对齐的后一个位置(比如右下角p的next值为2,数组下标2位置前就是对上的前缀)!!![这点是后面实现的核心]

2.所以这次的判断会决定下一次的next结果(核心问题单独讨论)

如何才能让,所谓判断会决定下一次的next结果

1.在循环外,先将0位置next为-1

2.i设置为next的下标,j处理后是填入next数组的数据,我们需要做的就是用i来遍历next,并且将j值赋给next数组。使用while语句,更方便控制。

3.循环开始前的最后准备:由于开始i=0,j就应该是-1,这样就匹配上数组i位置值为j

4.由于一个位置反映前面的情况,我们是由0开始的,那么就是由i定i+1位置的next值。

5.如果j==-1,说明是i是0位置,那么我们要做的就是把1位置的next赋值为0,简单将就是next[++i]=++j;这样i往后走了,j也是i往后走对应的next值

6.此时是最关键的一步

我们的 i 往后走了一步,现在要确定的就是i+1反映的是 i 跟前面内容的关系

假设我们已经得到了很多next值了,其本质我们也清楚了

1.最简单的就是i位置和对应j下标位置的值一样,说明此时最长前缀后面加一个字符,它也是对上的,那么其实++i位置的next等于++j

2.不相等,则更新将j更新为k,因为此时两边是对不上的,那么后面那一串就没有意义了,需要重新和前面的部分对应。但是前面部分我们已经知道情况了,所以j更新到k位置,那么更新后j的k值又会回到上面的判断(判断i+1位置和j对应的k位置到底对不对的上)。如果找不到就循环第二步,找到就走第一步。

class Solution {
public:
    void getNext(string& needle,vector<int> &next)
    {
        next[0]=-1;
        int i=0, j=-1;
        while(i<needle.size()-1)
        {
            if(j==-1||needle[i]==needle[j]){
                next[++i]=++j;
            }
            else
            {
                j=next[j];
            }   
        }
    }

    int getTarget(string& haystack, string& needle,vector<int> &next)
    {
        int i=0,j=0;
        while(i<haystack.size())
        {
            if(haystack[i]==needle[j])
            {
                if(j==needle.size()-1)
                    return i-j;
                i++;
                j++;
            }
            else if(j==0)
            {
                i++;
            }
            else
                j=next[j];
        }
        return -1;
    }

    int strStr(string haystack, string needle) {
        vector<int> next(needle.size(),0);
        getNext(needle,next);
        return getTarget(haystack,needle,next);
    }
};

2.重复的子字符串

​​​​​​459. 重复的子字符串

实现其实很简单,s加成一倍,掐头去尾。如果还能在这个字符串里找到s就说明是重复的,反之不是。

class Solution {
public:
    bool repeatedSubstringPattern(string s) {
        string tmp(s.begin()+1,s.end());
        tmp+=s;
        tmp.erase(tmp.size()-1);
        cout<<tmp;
        if(tmp.find(s)==string::npos)
            return false;
        return true;
    }
};
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

哈里沃克

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值