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

本题使用的方法为 KMP 算法,KMP算法是一种字符串匹配算法,全称是 Knuth-Morris-Pratt 算法,主要思想是利用已知信息来避免无效的字符比较,从而提高匹配效率。

本题关键点在于构建 next 跳转表,难点在于在getNext 和 strStr 函数中理清 while 不匹配时的逻辑,不匹配的代码需要放在 if 匹配的代码前面,这样在不匹配回退到下标0时还可以对文本串当前的字符和模式串最开始的字符进行匹配,不然会导致如果文本串当前是匹配的,却因为下标++匹配掉了。

时间复杂度:O(m+n),空间复杂度:O(n),其中m为文本串haystack的长度,n为模式串needle的长度。

getNext 函数思路:

  1. 初始化 j 为0,next[0] 为 0,表示第一个字符不存在前缀和后缀,从第二个字符开始遍历。
  2. 在遍历过程中,比较 s[i] 和 s[j] 是否相等,如果不相等,则j向前回退,更新 j 值为 next[j-1],并重复该步骤,直到 j 为 0 或者 s[i] 和 s[j] 相等。
  3. 当 s[i] 和 s[j] 相等时,将 j 加1,表示匹配成功的子字符串长度,同时将 j 值赋给 next[i],记录在该位置上前缀和后缀匹配的长度,同时也是在遇到冲突时,在这种前缀情况下应该返回的位置。最后遍历完毕后,得到 next 数组。

strStr 函数思路:

  1. 从前往后遍历文本串 haystack,以 fast 指针记录当前匹配的位置。
  2. 在遍历文本串时,如果当前字符与模式串的对应位置不同,则需要将模式串的指针根据 next 数组中发生冲突位置的上一个位置的值进行回退,回到上一个匹配的位置。
  3. 如果文本串当前字符与模式串的对应位置相同,则将模式串和文本串指针向后移动一位。
  4. 如果到达模式串的末尾,则说明文本串 haystack 中出现了完整的模式串 needle,返回用当前位置计算的匹配的起始位置。

代码:

class Solution {
public:
    void getNext(int *next, string &s) {
        int j = 0; // j是匹配的前缀的末尾,同时也是匹配的子字符串的长度
        next[j] = 0;
        for (int i = 1; i < s.length(); i++) { // i是匹配的后缀的末尾
            while (s[i] != s[j] && j > 0) { // 前后缀不相同了,while是因为可能出现多次回退的情况
                j = next[j - 1]; // 向前回退
                // next[i] = j; // 同下
            }
            if (s[i] == s[j]) { // 找到了相同的前后缀
                j++;
                // next[i] = j; // 将j(匹配的子字符串的长度)赋给next[i],即在遇到冲突时,在这种前缀情况下应该返回哪个地方继续匹配
            }
            next[i] = j; // 写在外面是因为当j=0时,s[i]和s[j]不匹配也要给next[i]赋值
        }
    }

    int strStr(string haystack, string needle) {
        if (needle.length() == 0)
            return 0;
        int next[needle.length()];
        getNext(next, needle);
        int i = 0; // needleIndex
        for (int fast = 0; fast < haystack.length(); fast++) {
            while (haystack[fast] != needle[i] && i > 0) { // 不匹配
                i = next[i - 1]; // 寻找之前匹配的位置
            }
            if (haystack[fast] == needle[i]) { // 匹配,fast和i同时向后移动,fast的移动在for循环里
                i++;
                if (i == needle.length()) // 文本串haystack里出现了完整的模式串needle
                    return (fast - needle.size() + 1);
            }
        }
        return -1;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值