27-算法打卡-字符串-找出字符串中第一个匹配项的下标-leetcode(28)-第二十七天

1 题目地址

28. 找出字符串中第一个匹配项的下标 - 力扣(LeetCode)28. 找出字符串中第一个匹配项的下标 - 给你两个字符串 haystack 和 needle ,请你在 haystack 字符串中找出 needle 字符串的第一个匹配项的下标(下标从 0 开始)。如果 needle 不是 haystack 的一部分,则返回  -1 。 示例 1:输入:haystack = "sadbutsad", needle = "sad"输出:0解释:"sad" 在下标 0 和 6 处匹配。第一个匹配项的下标是 0 ,所以返回 0 。示例 2:输入:haystack = "leetcode", needle = "leeto"输出:-1解释:"leeto" 没有在 "leetcode" 中出现,所以返回 -1 。 提示: * 1 <= haystack.length, needle.length <= 104 * haystack 和 needle 仅由小写英文字符组成https://leetcode.cn/problems/find-the-index-of-the-first-occurrence-in-a-string/description/


2 题目说明

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

示例 1:

输入:haystack = "sadbutsad", needle = "sad"
输出:0
解释:"sad" 在下标 0 和 6 处匹配。
第一个匹配项的下标是 0 ,所以返回 0 。

示例 2:

输入:haystack = "leetcode", needle = "leeto"
输出:-1
解释:"leeto" 没有在 "leetcode" 中出现,所以返回 -1 。

提示:

  • 1 <= haystack.length, needle.length <= 104
  • haystack 和 needle 仅由小写英文字符组成

3 解题思路

方式一:暴力方式:两层循环
1、假设字符串haystack长度是m,needle长度是n
2、haystack匹配needle最多需要循环次数是m-n+1
3、第一层循环是最多需要遍历的次数m-n+1,即haystack的起始的索引下标位置
4、第二层循环每次都是从0开始最大到needle长度n,判断两层的指向的字符是否相等,
        不相等:直接跳出第二层循环
        相等:第二层是否遍历到needle的末尾
                是:直接返回第一层索引下标(结果)
                否:上下两层同时向后移动

方式二:KMP

查看 28-算法打卡-字符串-KMP算法理论-第二十八天-CSDN博客29-算法打卡-字符串-KMP算法理论2-第二十九天-CSDN博客

核心思想是记录已经遍历过的模式串的特征,当匹配失败的时候只需要模式串退回,文本串继续向右移动,减少时间复杂度O(m+n)。

 获取前缀表(next数组):
1、初始化:初始化指针i j, j指向前缀的末尾也是子串的最长公共前后缀、i指向后缀的
末尾也是待更新next数组的位置; j=0,next[0]=0
2、前后缀相同: j向右移动,next[i]=j
3、前后缀不相同:j回退到next[j-1]位置 ,不相等一直回退,即是while,而不是if

4、更新next数组,next[i]=j

 获取匹配下标:

1、获取next数组

2、定义指针i j,i指向haystack 开始位置(0), j指向needle开始位置(0)

3、文本串和模式串指向的位置相同时:则两者都继续向右移动
4、文本串和模式串指向的位置不相同时:模式串退回到next[j-1]的位置

4 代码编写


4.1 暴力方式

class Solution {
    public int strStr(String haystack, String needle) {
      char[] haystackArray = haystack.toCharArray();
      char[] needleArray = needle.toCharArray();
      int haystackLength = haystackArray.length;
      int needleLength = needleArray.length;
      // 需要匹配的次数
      int need = haystackLength - needleLength + 1;
      for (int i=0; i<need; i++) {
            int left = i;
            int needleInit = 0;
            while (needleInit<needleLength) {
                // 字符相等
                if (haystackArray[left] == needleArray[needleInit]) {
                    // 最后一个元素也匹配直接返回
                    if (needleInit == needleLength-1) {
                        return i;
                    }
                    // 否则都向后移动
                    left++;
                    needleInit++;
                } else {
                     // 不相等,直接跳出本层循环
                    break;
                }
            }
      }
      return -1;
    }

}

简化上面代码方式:

class Solution {
    public int strStr(String haystack, String needle) {
      char[] haystackArray = haystack.toCharArray();
      char[] needleArray = needle.toCharArray();
      int haystackLength = haystackArray.length;
      int needleLength = needleArray.length;
      // 需要匹配的次数
      int need = haystackLength - needleLength + 1;
      for (int i=0; i<need; i++) {
            int left = i;
            int needleInit = 0;
            // 匹配则向后移动
            while (needleInit<needleLength && haystackArray[left] == needleArray[needleInit]) {
                left++;
                needleInit++;
            }
            // 最后一个元素也匹配直接返回
            if (needleInit == needleLength) {
                return i;
            }
      }
      return -1;
    }

}


4.2 KMP

class Solution {
    public int strStr(String haystack, String needle) {
        int m = haystack.length();
        int n = needle.length();
        int[] next = new int[n];
        getNext(needle, next);
        int j = 0;
        for (int i=0; i<m; i++) {
            while (j>0 && haystack.charAt(i) != needle.charAt(j)) {
                j = next[j-1];
            }
            if (haystack.charAt(i) == needle.charAt(j)) {
                j++;
            }
            if (j==n) {
                return (i-j+1);
            }
        }

        return -1;
    }

    // 获取前缀表
    public void getNext(String needle, int[] next) {
        // 初始化,j后缀的末尾,子串的最长公共前后缀
        int j = 0;
        next[0] = 0;
        // i前缀的末尾,数组next更新索引位置
        for (int i=1; i<needle.length(); i++) {
            while (j>0 && needle.charAt(i)!= needle.charAt(j)) {
                // 向左回退
                j = next[j-1];
            }
            // 匹配成功向右移动
            if (needle.charAt(i)== needle.charAt(j)) {
                    j++;
            }
            // 更新数组
            next[i] = j;
        }

    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值