Leetcode-找出字符串中第一个匹配的下标(C++)

一、题目

给你两个字符串 haystack 和 needle ,请你在 haystack 字符串中找出 needle 字符串的第一个匹配项的下标(下标从 0 开始)。如果 needle 不是 haystack 的一部分,则返回  -1 

 这个题目其实是在实现string的内置函数find()。find()函数用的很广,需要包含<algorithm>,主要用在查找容器的某个对象,返回值是迭代器,用在string中,主要用于查找指定字符和子串,返回值是下标。

可以使用字符串匹配算法解决,常见的字符串匹配算法包括暴力匹配、Knuth-Morris-Pratt 算法、Boyer-Moore 算法、Sunday 算法等。

二、暴力匹配

这是leetcode中的简单题,我首先想到的就是“暴力解法”,即通过遍历判断是否符合题意,如果找到了就返回下标,没找到就跳出循环。思路较简单,下面是我的1.0版代码(不能正确运行)。

在执行string haystack= "leetcode";string needle = "leeto";时出现错误,本应该输出-1,但却输出了5。代码没有语句错误,逻辑错误很难找出来,在这里我花了很长时间找错。

class Solution {
public:
    int strStr(string haystack, string needle) {
        int num1=strlen(haystack.c_str());
        int num2=strlen(needle.c_str());
        for(int i=0;i<num1;i++){
            int temp=i;
            for(int j=0;j<num2;j++){
                if(haystack[temp]==needle[j]){
                    temp++;
                }
                else{
                    continue;
                }
                if(j==num2-1){
                    return i;
                }
            }
        }
        return -1;
    }
};

最后发现,需要将continue变成break。break用于完全结束一个循环,跳出循环体执行循环后面的语句,而continue用于跳过本次循环,直接进入下一次循环,continue不会结束整个循环的执行,而是结束本次循环,继续执行后续的循环语句在此错误使用continue的话,会造成资源浪费和判断不准确。

下面是2.0版本代码(运行成功)。

class Solution {
public:
    int strStr(string haystack, string needle) {
        int num1=strlen(haystack.c_str());
        int num2=strlen(needle.c_str());
        for(int i=0;i<num1;i++){
            int temp=i;
            for(int j=0;j<num2;j++){
                if(haystack[temp]==needle[j]){
                    temp++;
                }
                else{
                    break;
                }
                if(j==num2-1){
                    return i;
                }
            }
        }
        return -1;
    }
};

以下是运行效率。这个执行用时这么短是我没想到的。。

三、Knuth-Morris-Pratt (KMP)算法

KMP?KFC?作为小白,确实没听过这个算法。相对文字,本人更喜欢视频,下面推荐一个B站大学的视频。

【最浅显易懂的 KMP 算法讲解】 https://www.bilibili.com/video/BV1AY4y157yL/?share_source=copy_web&vd_source=1c40518818373e585c08ba3456deee48

 本网站中也有很多佬写了算法解析,这位博主写得很清晰。

http://t.csdnimg.cn/nnlA7

了解了算法原理,那么我们就能用优化方法解该题了。

解析过程比较复杂,参考leetcode官网,讲得很详细,图文并茂。

. - 力扣(LeetCode)

代码如下。

class Solution {
public:
    int strStr(string haystack, string needle) {
        int n = haystack.size(), m = needle.size();
        if (m == 0) {
            return 0;
        }
        vector<int> pi(m);
        for (int i = 1, j = 0; i < m; i++) {
            while (j > 0 && needle[i] != needle[j]) {
                j = pi[j - 1];
            }
            if (needle[i] == needle[j]) {
                j++;
            }
            pi[i] = j;
        }
        for (int i = 0, j = 0; i < n; i++) {
            while (j > 0 && haystack[i] != needle[j]) {
                j = pi[j - 1];
            }
            if (haystack[i] == needle[j]) {
                j++;
            }
            if (j == m) {
                return i - m + 1;
            }
        }
        return -1;
    }
};

作者:力扣官方题解
链接:https://leetcode.cn/problems/find-the-index-of-the-first-occurrence-in-a-string/solutions/732236/shi-xian-strstr-by-leetcode-solution-ds6y/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

讲真,上面这玩意儿,不理解KMP算法真的很难搞懂。 

四、Sunday算法

第一步,搞懂原理。不得不说,这些首次提出一个优化算法的大佬真厉害。下面是一个博主讲的算法原理。

http://t.csdnimg.cn/tIUBa

直接上代码了。

class Solution {
public:
    int strStr(string haystack, string needle) {
        if(needle.empty())
            return 0;
        
        int slen=haystack.size();
        int tlen=needle.size();
        int i=0,j=0;//i指向源串首位 j指向子串首位
        int k;
        int m=tlen;//第一次匹配时 源串中参与匹配的元素的下一位
        
        for(;i<slen;)
        {
            if(haystack[i]!=needle[j])
            {
                for(k=tlen-1;k>=0;k--)//遍历查找此时子串与源串[i+tlen+1]相等的最右位置
                {
                    if(needle[k]==haystack[m])
                        break;
                }
                i=m-k;//i为下一次匹配源串开始首位 Sunday算法核心:最大限度跳过相同元素
                j=0;//j依然为子串首位
                m=i+tlen;//m为下一次参与匹配的源串最后一位元素的下一位
                if(m>slen)//当下一次参与匹配的源串字数的最后一位的下一位超过源串长度时
                    return -1;
            }
            else
            {
                if(j==tlen-1)//若j为子串末位 匹配成功 返回源串此时匹配首位
                    return i-j;
                i++;
                j++;
            }
        }
        return -1;//当超过源串长度时 
    }
};

作者:西野七瀬
链接:https://leetcode.cn/problems/find-the-index-of-the-first-occurrence-in-a-string/solutions/6920/c5chong-jie-fa-ku-han-shu-bfkmpbmsunday-by-2227/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值