力扣面试经典算法150题:找出字符串中第一个匹配项的下标

找出字符串中第一个匹配项的下标

今天的题目是力扣面试经典150题中的数组的简单题: 找出字符串中第一个匹配项的下标

题目链接:https://leetcode.cn/problems/find-the-index-of-the-first-occurrence-in-a-string/description/?envType=study-plan-v2&envId=top-interview-150

题目描述

给定一个字符串 haystack 和一个字符串 needle,请找出 needle 在 haystack 中第一次出现的位置(下标)。如果 needle 不是 haystack 的一部分,则返回 -1。

  • 示例:
    • 输入:
      haystack = "hello", needle = "ll"
    • 输出:
      2
    • 输入:
      haystack = "aaaaa", needle = "bba"
    • 输出:
      -1

题目分析

题目要求我们在一个字符串 haystack 中找到另一个字符串 needle 第一次出现的位置。如果 needle 不是 haystack 的一部分,则返回 -1。

很明显,字符串needle是被包含在haystack中的一个子串,这意味着needle的字符在haystack中连续出现。

只需要第一次出现的位置则意味着我们需要的结果是needle中的字符第一次在haystack中连续出现时的第一个字符在haystack中的下标。

解题思路

分隔法

第一时间想到的办法:

  1. 判断haystack是否包含needle,不包含直接返回-1。
  2. 判断haystack是否以needle开头, 是的话返回0。
  3. 使用needle分割haystack,获取第一段的字符串长度返回即可。

整串匹配法

在分割法之后再思考想到的办法,使用整个子串去匹配:

  1. 获取两个字符串的长度。
  2. 以两者差值作为循环条件进行循环。
  3. 截取当前下标开始到子串长度的字符串与子串对比,一致则返回下标的值。
  4. 返回-1。

单字符匹配法:

在整串匹配法后想到的,不截取字符串,直接依次比较每个字符:

  1. 获取两个字符串的长度。
  2. 以两者差值作为循环条件进行循环
  3. 从 haystack 的第一个字符开始,逐个字符比较。
  4. 如果发现 haystack 中有一段子串与 needle 相同,则返回这段子串的起始位置。
  5. 如果遍历完整个 haystack 都没有找到匹配的子串,则返回 -1。

KMP 算法:

在上诉方法用完以后,尝试找到该类型题目的特殊算法:

  1. 构建 KMP 的 next 数组,然后根据 next 数组进行快速匹配。
  2. 如果找到匹配的子串,则返回起始位置;否则,返回 -1。

有点抽象,没完全想明白,这里就不贴了。。。

实际算法代码

下面是使用三种方法的 Java 实现:

java 复制代码
public static void main(String[] args) {
        StrStr solution = new StrStr();

        // 示例数据
        String haystack = "hello";
        String needle = "ll";

        // 调用计算第一个匹配项下标的方法
        int index1 = solution.strStr1(haystack, needle);
        int index2 = solution.strStr2(haystack, needle);
        int index3 = solution.strStr3(haystack, needle);

        // 输出结果
        System.out.println("The index1 of the first occurrence is: " + index1);
        System.out.println("The index2 of the first occurrence is: " + index2);
        System.out.println("The index3 of the first occurrence is: " + index3);
    }

    /**
     * 查找字符串中第一个匹配项的下标: 分割法
     *
     * @param haystack 主字符串
     * @param needle   子字符串
     * @return 第一个匹配项的下标
     */
    public int strStr1(String haystack, String needle) {
        if (needle.isEmpty()) {
            return 0;
        }

        if (!haystack.contains(needle)) {
            return -1;
        }
        if (haystack.startsWith(needle)) {
            return 0;
        }
        String[] split = haystack.split(needle);
        if (split.length > 0) {
            return split[0].length();
        }
        return -1;
    }


    /**
     * 查找字符串中第一个匹配项的下标:整串匹配法
     *
     * @param haystack 主字符串
     * @param needle   子字符串
     * @return 第一个匹配项的下标
     */
    public int strStr2(String haystack, String needle) {
        if (needle.isEmpty()) {
            return 0;
        }

        int n = haystack.length();
        int m = needle.length();

        for (int i = 0; i <= n - m; i++) {
            if (needle.equals(haystack.substring(i, i + m))) {
                return i;
            }
        }

        return -1;
    }

    /**
     * 查找字符串中第一个匹配项的下标:单字符匹配法
     *
     * @param haystack 主字符串
     * @param needle   子字符串
     * @return 第一个匹配项的下标
     */
    public int strStr3(String haystack, String needle) {
        if (needle.isEmpty()) {
            return 0;
        }

        int n = haystack.length();
        int m = needle.length();

        for (int i = 0; i <= n - m; i++) {
            boolean found = true;
            for (int j = 0; j < m; j++) {
                if (haystack.charAt(i + j) != needle.charAt(j)) {
                    found = false;
                    break;
                }
            }
            if (found) {
                return i;
            }
        }

        return -1;
    }

结果

同时调用三个方法,返回结果都符合预期:

我们分别提交到力扣:

通过肯定都是通过的,这里贴第三种方法的图,因为这个方法的相对最优。

以下是三种方法的提交结果:

  1. 分割法
  1. 整串匹配法
  1. 单字符匹配法

三种方法最先能想到的容易程度以及理解难度正好按与算法的效果相反,难道这就是算法吗

总结

今天自己想了三种方法,特殊算法KMP有点抽象一下子还没想明白,有兴趣的自行学习,明天我再抽空理解一下。

另外数组简单难度的题目已经做完,下面开始上强度了。。。

加油!!!

相关推荐
清梦202020 分钟前
经典问题---跳跃游戏II(贪心算法)
算法·游戏·贪心算法
Wyang_XXX42 分钟前
CSS 选择器和优先级权重计算这么简单,你还没掌握?一篇文章让你轻松通关面试!(下)
面试
Dream_Snowar42 分钟前
速通Python 第四节——函数
开发语言·python·算法
星河梦瑾44 分钟前
SpringBoot相关漏洞学习资料
java·经验分享·spring boot·安全
黄名富1 小时前
Redis 附加功能(二)— 自动过期、流水线与事务及Lua脚本
java·数据库·redis·lua
love静思冥想1 小时前
JMeter 使用详解
java·jmeter
言、雲1 小时前
从tryLock()源码来出发,解析Redisson的重试机制和看门狗机制
java·开发语言·数据库
Altair澳汰尔1 小时前
数据分析和AI丨知识图谱,AI革命中数据集成和模型构建的关键推动者
人工智能·算法·机器学习·数据分析·知识图谱
TT哇1 小时前
【数据结构练习题】链表与LinkedList
java·数据结构·链表
A懿轩A1 小时前
C/C++ 数据结构与算法【栈和队列】 栈+队列详细解析【日常学习,考研必备】带图+详细代码
c语言·数据结构·c++·学习·考研·算法·栈和队列