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

题目来源:https://leetcode.cn/problems/find-the-index-of-the-first-occurrence-in-a-string/description/

 C++题解1:使用两个for循环,对于haystack的每个字符都判断是否为匹配项,直至找到或结尾(剩余长度小于needle)

class Solution {
public:
    int strStr(string haystack, string needle) {
        int lenh = haystack.size();
        int lenn = needle.size();
        int flg = -1;
        for(int ii = 0; ii < lenh - lenn + 1; ii++){
            for(int jj = 0; jj < lenn; jj++){
                flg = ii;
                if(haystack[ii + jj] != needle[jj]) {
                    flg = -1;
                    break;
                }
            }
            if(flg != -1) break;
        }
        return flg;
    }
};

C++题解2:使用KMP算法,下面两个链接反复看就能看懂,模式串可能用‘aabaabaac’会好理解

思路理解:KMP 算法详解 - 知乎

代码参考:代码随想录

一点点小结:写代码的时候主要分两个内外循环。

(1)第一个内外循环是求next数组,时间复杂度是O(m);第二个内外循环是求匹配项,在匹配的过程中,根据前缀表不断调整匹配的位置,可以看出匹配的过程是O(n)。

(2)两个内外循环很相似。外循环是模式串/字符串的索引更新,这个循环容易理解;内循环是匹配状态的更新,主要是在不匹配情况下,前缀表的回退状态,因为有可能一直回退,所以需要用一个while循环。

(3)注意状态跳转的jj表示跳转到模式串对应的索引上,所以第一个next[0]是-1,而“aabaabaac”的next[1]则是0,next[2]是1,依次类推,next={-1, 0, -1, 0, 1, 2, 3, 4, -1}。举例说明:假设目标字符串匹配了第一个a之后,第二个a如果匹配就继续往前走,如果不匹配就跳转到next[1](即对应索引为0),去看是否匹配第一个'a'; 假设目标字符串匹配到倒数第二个a,接下来它去匹配最后一个a,发现匹配往前走,发现不匹配,它就会跳到next[7](即索引4)的位置,然后发现跟索引next[4](即索引1)的位置也不匹配,就跳到next[1](即索引0)的位置,这样也避免了一个一个的麻烦。

class Solution {
public:
    int strStr(string haystack, string needle) {
        int lenh = haystack.size();
        int lenn = needle.size();
        if(lenh < lenn) return -1;

        //求解模式串needl的next数组
        int jj = -1;   //jj表示状态,从-1开始
        int next[lenn];
        next[0] = -1;
        for(int ii = 1; ii < lenn; ii++){
            while(jj >= 0 && needle[ii] != needle[jj + 1]) {
                jj = next[jj];
            }
            if(needle[ii] == needle[jj + 1]) jj++;
            next[ii] = jj;
            // 打印next数组
            // cout<<ii<<"  "<<next[ii]<<endl;
        }

        // 求解目标字符串的匹配索引,jj还是从-1开始
        // 下面的两个循环与上面两个循环其实很相似,只是上面的外字符串为needle,下面的为haystack
        jj = -1;
        for(int mm = 0; mm < lenh; mm++) {
            while(jj >= 0 && haystack[mm] != needle[jj + 1]) {
                jj = next[jj];
            }
            if(haystack[mm] == needle[jj + 1]) jj++;
            if(jj == lenn - 1) {
                return mm - lenn + 1;
            }
        }
        return -1;
    }
};

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值