Leetcode(28)——实现 strStr()

Leetcode(28)——实现 strStr()

题目

实现 strStr() 函数。
给你两个字符串 haystack 和 needle ,请你在 haystack 字符串中找出 needle 字符串出现的第一个位置(下标从 0 0 0 开始)。如果不存在,则返回 − 1 -1 1

说明:

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

示例 1:

输入:haystack = “hello”, needle = “ll”
输出:2

示例 2:

输入:haystack = “aaaaa”, needle = “bba”
输出:-1

提示:

  • 1 1 1 <= haystack.length, needle.length <= 1 0 4 10^4 104
  • h a y s t a c k haystack haystack n e e d l e needle needle 仅由小写英文字符组成

题解

方法一:KMP算法——优化的nextval数组

思路

​​  本题是经典的字符串单模匹配的模型,因此可以使用字符串匹配算法解决,常见的字符串匹配算法包括暴力匹配、 Knuth-Morris-Pratt \text{Knuth-Morris-Pratt} Knuth-Morris-Pratt 算法、 Boyer-Moore \text{Boyer-Moore} Boyer-Moore 算法、 Sunday \text{Sunday} Sunday 算法等, 这里我们使用了 Knuth-Morris-Pratt \text{Knuth-Morris-Pratt} Knuth-Morris-Pratt 算法。

​​  关于 KMP 算法最特别的就是 next 数组和优化后的 nextval 数组了,这里不会讲解 KMP 算法,需要的可以自己去网上查找。

代码实现
class Solution {
    void get_nextval(int* nextval, const string& needle){
        int i=0, j=-1;  // i表示后缀的单个字符下标,j表示前缀的单个字符下标
        nextval[0] = -1;
        // 求nextval数组
        while(i < needle.length()-1){   // 修改的是 nextval[i] 的值
            if(j == -1 || needle[i] == needle[j]){
                ++i;
                ++j;
                if(needle[i] != needle[j]) nextval[i]=j;
                else nextval[i] = nextval[j];
                nextval[i] = j;
            }else j = nextval[j];
        }
    }
public:
    int strStr(string haystack, string needle) {
        if(needle.length() == 0) return 0;
        // 采用KMP匹配算法
        int nextval[needle.length()];
        get_nextval(nextval, needle);
        int l1=haystack.length(), l2=needle.length();
        int i = 0, j = 0;   // i为主串 haystack 当前字符的下标,j为子串 needle 当前字符的下标
        while(i < l1 && j < l2){
            if(j==-1 || haystack[i] == needle[j]){
                ++i;
                ++j;
            }else j = nextval[j];
            // 不能直接比较,size_type为无符号类型,int为有符号类型,
            // 如果int为负数时,假设为-1,他会先转换成无符号整形再与size_type变量进行比较,此时可能会出现-1>正数的情况
            if(l2 == j)
                return i-j;
        }
        return -1;
    }
};
复杂度分析

时间复杂度 O ( n + m ) O(n+m) O(n+m),其中 n n n 是字符串 haystack \textit{haystack} haystack 的长度, m m m 是字符串 needle \textit{needle} needle 的长度。我们至多需要遍历两字符串一次。
空间复杂度 O ( m ) O(m) O(m) m m m 是字符串 needle \textit{needle} needle 的长度。我们只需要保存字符串 needle \textit{needle} needle 的前缀。

方法二:暴力匹配

思路

​​  我们可以让字符串 needle \textit{needle} needle 与字符串 haystack \textit{haystack} haystack 的所有长度为 m m m 的子串均匹配一次。

​​  为了减少不必要的匹配,我们每次匹配失败即立刻停止当前子串的匹配,对下一个子串继续匹配。如果当前子串匹配成功,我们返回当前子串的开始位置即可。如果所有子串都匹配失败,则返回 − 1 -1 1

代码实现
class Solution {
public:
    int strStr(string haystack, string needle) {
        int n = haystack.size(), m = needle.size();
        for (int i = 0; i + m <= n; i++) {
            bool flag = true;
            for (int j = 0; j < m; j++) {
                if (haystack[i + j] != needle[j]) {
                    flag = false;
                    break;
                }
            }
            if (flag) {
                return i;
            }
        }
        return -1;
    }
};
复杂度分析

时间复杂度 O ( n × m ) O(n \times m) O(n×m),其中 n n n 是字符串 haystack \textit{haystack} haystack 的长度, m m m 是字符串 needle \textit{needle} needle 的长度。最坏情况下我们需要将字符串 needle \textit{needle} needle 与字符串 haystack \textit{haystack} haystack 的所有长度为 m m m 的子串均匹配一次。
空间复杂度 O ( 1 ) O(1) O(1)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值