LeetCode初级算法之字符串:实现strStr

题目描述
实现 strStr() 函数。

给定一个 haystack 字符串和一个 needle 字符串,在 haystack 字符串中找出 needle 字符串出现的第一个位置 (从0开始)。如果不存在,则返回 -1。

示例 1:
输入: haystack = “hello”, needle = “ll”
输出: 2
示例 2:
输入: haystack = “aaaaa”, needle = “bba”
输出: -1
说明:

当 needle 是空字符串时,我们应当返回什么值呢?这是一个在面试中很好的问题。
对于本题而言,当 needle 是空字符串时我们应当返回 0 。这与C语言的 strstr() 以及 Java的 indexOf() 定义相符。

思路:
这个题其实可以直接调用string的find函数

haystack.find(needle)  // 直接得到答案

但是,如果调用库函数,失去了这个题的意义了,是让自己实现。
其实简单想到的方式就是暴力了,所以我的第一版代码就是暴力,就是遍历haystack,然后对于每一个字符,遍历needle,看看能不能匹配上,如果匹配完毕,直接返回位置,否则,i向后移动,然后再来。

class Solution {
public:
    int strStr(string haystack, string needle) {

        int len1 = haystack.size();
        int len2 = needle.size();
        if (len2 == 0)
            return 0;
        if (len1 == 0)
            return -1;

        int loc = -1;
        for (int i=0; i<len1-len2+1; i++)
        {
            int j = 0;
            int temp = i;
            while(j<len2 && haystack[temp]==needle[j])
                {   j++;
                    temp++;
                }

            if (j==len2)
            {
                loc = i;
                break;
            }
        }

        return loc;
    }
};

但是,这个的时间复杂度有点高了,所以第二个就是BF算法了,其实也是一个暴力的方式。

class Solution
{
public:
    int strStr(string haystack, string needle)
    {
        if(needle.empty())
            return 0;

        int i=0,j=0;
        while(haystack[i]!='\0'&&needle[j]!='\0')
        {
            if(haystack[i]==needle[j])
            {
                i++;
                j++;
            }
            else
            {
                i=i-j+1;
                j=0;
            }
        }
        if(needle[j]=='\0')
            return i-j;

        return -1;
    }
}

下面有两种改进的方式,kMP算法和Sunday算法,KMP算法是构造一个next数组,是先考虑了needle字符串本身的特定,借助每一次比较,使得不重复比较,而Sunday算法是尽量的跳过一些重复的字符。具体的没太看明白,先记录下来

// KMP
class Solution {
public:
    int strStr(string haystack, string needle) {
        int n = haystack.size(), m = needle.size();
        if (m == 0) return 0;
        vector<int> ne(m + 1, -1);

        for (int i = 1, j = -1; i < m; i ++)
        {
            while (j != -1 && needle[i] != needle[j + 1])  j = ne[j];
            if (needle[i] == needle[j + 1])  j ++;
            ne[i] = j;
        }   // 生成next数组

        for (int i = 0, j  = -1; i < n; i ++)
        {
            while (j != -1  && haystack[i] != needle[j + 1])  j = ne[j];
            if (haystack[i] == needle[j + 1])  j ++;
            if (j == m - 1)  return i - m + 1;
        }
        return -1;
    }
};

// Sunday算法
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;//当超过源串长度时
    }
};

但是在这个题中,后面两个的速度并不是那么快,好像给出的样例没法使得后面两种算法发挥出优势。

发布了66 篇原创文章 · 获赞 67 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/wuzhongqiang/article/details/103301384