【28.实现strStr】

1.题目描述

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

  说明:

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

 输入:haystack = "hello", needle = "ll"
 输出:2

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

 输入:haystack = "", needle = ""
 输出:0

2.解题思路及具体代码

  • 方法一:简单截取

思路:
1,首先从开始位置遍历主串元素,直到找到第一个与子串第一字符相同的元素。
2,这个时候,截取主串相同子串长度的字符串与子串进行比较
3,注意,在截取时可能出现主串剩余长度小于子串长度,所以要加个限定条件。

具体代码如下:

 public int strStr(String haystack, String needle) {
        if (needle.length()==0){
            return 0;
        }
        int h=haystack.length();
        int n=needle.length();
        int result=-1;
        int i,j;
        i=j=0;
        while (i<h && j<n){
            if (haystack.charAt(i)==needle.charAt(j) && n<=(h-i)){
                if (haystack.substring(i,i+n).equals(needle)){
                    result=i;
                    break;
                }
            }
            i++;
        }
        return result;
    }

时间复杂度:substring的时间复杂度是O(n),那么substring这段代码可能会执行多次,这取决于两个值字符串的特点。因此大概猜测时间复杂度为O(M*N),M是主串的长度,N是子串 的长度。(这里可能有点问题,希望大家帮忙指正)
空间复杂度:O(l)

  • 方法二:KMP算法

解题思路:
这题妥妥的kmp算法解题,因为kmp算法就是在主串中寻找子串。
简单介绍kmp算法-得花点时间去理解,我这里只是快速介绍下kmp算法,有助于大家理解代码,尤其是next数组的生成。

kmp算法的作用是什么?

KMP的主要思想是当出现字符串不匹配时,可以知道一部分之前已经匹配的文本内容,可以利用这些信息避免从头再去做匹配了。(就是减少重复匹配的次数,从而降低时间复杂度)

kmp算法的关键是求next数组,那么next数组是用来干嘛的呢?
简单来说就是记录当前子串(从起始位置到当前数组下标位置)的最大相等前后缀。
前缀:去掉最后一个字符的剩余子串,如“aab”,前缀为“aa”。
后缀:去掉开始第一个字符的剩余子串,如"aab",后缀为"ab"。
什么是最大相等前后缀呢?
如“aab”,找到前缀中“aa”与后缀中“ab”的最大相同子串,如下图所示:

在这里插入图片描述
再如下图:
在这里插入图片描述
这样,只要给出一个字符串(一般我们叫模式串或子串),就可以求出它所对应的next数组的值。如下图计算next数组:
在这里插入图片描述那么kmp具体是减少匹配的次数的呢?(相较于朴素算法),如下图简单介绍下:

在这里插入图片描述上面只是简单介绍,如果是初学KMP算法的,建议找个视频,反复观看,搞懂里面的细节,这里不在描述。

下面是获取next数组的代码段(这里next数组内的前后缀数均减一):

public int[] getNext(char[] p1){
        int[] next=new int[p];
        int j=-1;
        next[0]=j;
        //获得next数组
        for (int i=1;i<needle.length();i++){
            while (j>=0 && p1[i]!=p1[j+1]){
                j=next[j];
            }

            if (p1[i]==p1[j+1]){
                j++;
            }
            next[i]=j;
        }
   }

另一方法是设置“哨兵”,即将数组第一位设置为空,在子串与主串匹配时,更容易理解,如下代码:

  public int[] getNext(char[] p){
// 构建 next 数组,数组长度为匹配串的长度(next 数组是和匹配串相关的)
            int m=p.length;
            int[] next = new int[m + 1];
            // 构造过程 i = 2,j = 0 开始,i 小于等于匹配串长度 【构造 i 从 2 开始】
                for (int i = 2, j = 0; i <= m; i++) {
                // 匹配不成功的话,j = next(j)
                while (j > 0 && p[i] != p[j + 1]) j = next[j];
                // 匹配成功的话,先让 j++
                if (p[i] == p[j + 1]) j++;
                // 更新 next[i],结束本次循环,i++
                next[i] = j;
            }
     }

整体实现代码如下:

   // KMP 算法
        // ss: 原串(string)  pp: 匹配串(pattern)
        public int strStr(String ss, String pp) {
            if (pp.isEmpty()) return 0;

            // 分别读取原串和匹配串的长度
            int n = ss.length(), m = pp.length();
            // 原串和匹配串前面都加空格,使其下标从 1 开始
            ss = " " + ss;
            pp = " " + pp;

            char[] s = ss.toCharArray();
            char[] p = pp.toCharArray();

            // 构建 next 数组,数组长度为匹配串的长度(next 数组是和匹配串相关的)
            int[] next = new int[m + 1];
            // 构造过程 i = 2,j = 0 开始,i 小于等于匹配串长度 【构造 i 从 2 开始】
                for (int i = 2, j = 0; i <= m; i++) {
                // 匹配不成功的话,j = next(j)
                while (j > 0 && p[i] != p[j + 1]) j = next[j];
                // 匹配成功的话,先让 j++
                if (p[i] == p[j + 1]) j++;
                // 更新 next[i],结束本次循环,i++
                next[i] = j;
            }

            // 匹配过程,i = 1,j = 0 开始,i 小于等于原串长度 【匹配 i 从 1 开始】
            for (int i = 1, j = 0; i <= n; i++) {
                // 匹配不成功 j = next(j)
                while (j > 0 && s[i] != p[j + 1]) j = next[j];
                // 匹配成功的话,先让 j++,结束本次循环后 i++
                if (s[i] == p[j + 1]) j++;
                // 整一段匹配成功,直接返回下标
                if (j == m) return i - m;
            }

            return -1;
        }

时间复杂度:O(n×m),其中 n 是字符串 haystac的长度,m 是字符串 needle的长度。最坏情况下我们需要将字符串 needle与字符串 haystack的所有长度为 m 的子串均匹配一次。
空间复杂度:O(1)。我们只需要常数的空间保存若干变量。

题目链接:https://leetcode-cn.com/problems/implement-strstr

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值