找出字符串中第一个匹配项的下标 | LeetCode-28 | KMP算法 | next数组 | Java详细注释

news2024/9/21 2:35:42
🙋大家好!我是毛毛张!
🌈个人首页: 神马都会亿点点的毛毛张
🕹️KMP算法练习题

LeetCode链接:28. 找出字符串中第一个匹配项的下标

文章目录

  • 1.题目描述🍇
  • 2.题解🍉
    • 2.1 暴力解法🍋
    • 2.2 KMP算法🥭
      • 2.2.1 KMP写法1(不减1)🍏
      • 2.2.2 KMP写法2(减1)🍒
    • 2.3 KMP算法改进🫐
      • 2.3.1 写法1(不减1)🥝
      • 2.3.2 写法2(减1)🍅

1.题目描述🍇

给你两个字符串 haystackneedle ,请你在 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 < = h a y s t a c k . l e n g t h , n e e d l e . l e n g t h < = 1 0 4 1 <= haystack.length, needle.length <= 10^4 1<=haystack.length,needle.length<=104
  • haystackneedle 仅由小写英文字符组成

2.题解🍉

2.1 暴力解法🍋

class Solution {
    public int strStr(String haystack, String needle) {
        if (needle.length() == 0) return 0;// 如果 needle 是空字符串,返回 0,根据题目要求

        // 遍历 haystack,从索引 0 到 haystack.length() - needle.length()
        for (int i = 0; i <= haystack.length() - needle.length(); i++) {
            int j = 0;
            // 检查当前子串是否与 needle 匹配
            while (j < needle.length() && haystack.charAt(i + j) == needle.charAt(j)) {
                j++;
            }
            
            if (j == needle.length()) {// 如果 j 达到 needle.length(),说明完全匹配
                return i;
            }
        }
        
        return -1;// 如果没有找到匹配的子串,返回 -1
    }
}

2.2 KMP算法🥭

2.2.1 KMP写法1(不减1)🍏

class Solution {
    public int strStr(String haystack, String needle) {
        if (needle.length() == 0) return -1; // 如果 needle 是空字符串,返回 0,根据题目要求

        int[] next = getNext(needle);// 生成 needle 的前缀函数数组

        int j = 0; // 匹配指针,用于遍历 needle
        for (int i = 0; i < haystack.length(); i++) {
            // 当前字符不匹配时,根据前缀函数回退 j
            while (j > 0 && haystack.charAt(i) != needle.charAt(j)) j = next[j - 1];
            // 如果字符匹配,增加 j
            if (haystack.charAt(i) == needle.charAt(j)) j++;
            // 完全匹配,返回起始位置
            if (j == needle.length()) return i - needle.length() + 1;
        }
        // 如果没有找到匹配,返回 -1
        return -1;
    }

    // 生成前缀函数数组
    public int[] getNext(String s) {
        int n = s.length();
        int[] next = new int[n];
        int j = 0; // 前缀指针

        next[0] = 0; // 第一个字符的前缀长度为0

        for (int i = 1; i < n; i++) {
            // 当前字符不匹配时,回退前缀指针 j
            while (j > 0 && s.charAt(i) != s.charAt(j)) j = next[j - 1];
            // 如果字符匹配,前缀长度增加
            if (s.charAt(i) == s.charAt(j)) j++;
            // 记录前缀长度到 next 数组
            next[i] = j;
        }
        return next;
    }
}

2.2.2 KMP写法2(减1)🍒

class Solution {
    public int strStr(String haystack, String needle) {
        // 如果 needle 是空字符串,返回 -1(根据题目要求)
        if (needle.length() == 0) return -1;

        // 生成 needle 的前缀函数数组,用于 KMP 算法
        int[] next = getNext(needle);
        int j = -1;// 匹配指针 j,用于遍历 needle。初始值为 -1,表示还没有匹配任何字符

        // 遍历 haystack 中的每个字符
        for (int i = 0; i < haystack.length(); i++) {
            // 当前字符不匹配时,根据前缀函数回退 j,直到找到一个可匹配的前缀位置或 j 变为 -1
            while (j >= 0 && haystack.charAt(i) != needle.charAt(j + 1)) j = next[j];

            // 如果当前字符匹配,增加 j 以匹配 needle 的下一个字符
            if (haystack.charAt(i) == needle.charAt(j + 1)) j++;

            // 如果 j 达到了 needle 的最后一个字符的位置,表示找到了匹配的子串
            if (j == needle.length() - 1) return i - needle.length() + 1;     
        }
        return -1;// 如果没有找到匹配的子串,返回 -1
    }

    // 生成前缀函数数组 next,用于 KMP 算法
    public int[] getNext(String s) {
        int n = s.length();
        int[] next = new int[n];
        int j = -1;// 前缀指针 j,初始值为 -1,表示还没有匹配任何前缀
        next[0] = -1;// next[0] 初始化为 -1,表示第一个字符没有前缀

        // 从第二个字符开始,遍历整个字符串 s
        for (int i = 1; i < n; i++) {
            // 当前字符不匹配时,回退前缀指针 j,直到找到一个可匹配的前缀位置或 j 变为 -1
            while (j >= 0 && s.charAt(i) != s.charAt(j + 1)) j = next[j];

            if (s.charAt(i) == s.charAt(j + 1)) j++;// 如果当前字符匹配,增加 j 以匹配下一个字符
            next[i] = j; // 记录前缀长度到 next 数组
        }
        return next;
    }
}

2.3 KMP算法改进🫐

  • nextval 数组是对 next 数组的进一步优化,主要用于加快失配后的回溯过程。nextval 数组在失配时可以避免一些不必要的匹配操作,从而提高算法的效率。

2.3.1 写法1(不减1)🥝

// 生成优化后的前缀函数数组 nextval
public int[] getNextval(String s) {
    int n = s.length();
    int[] nextval = new int[n];
    int j = 0; // 前缀指针

    nextval[0] = -1; // 第一个字符的前缀长度设为 -1

    for (int i = 1; i < n; i++) {
        // 当前字符不匹配时,回退前缀指针 j
        while (j > 0 && s.charAt(i) != s.charAt(j + 1)) {
            j = nextval[j]; // 根据 nextval 数组回退
        }
        // 如果字符匹配,前缀长度增加
        if (s.charAt(i) == s.charAt(j + 1)) {
            j++;
        }
        // 记录当前字符的前缀长度到 nextval 数组
        nextval[i] = j; // 当前字符的前缀长度
    }
    return nextval;
}

2.3.2 写法2(减1)🍅

public int[] getNextval(String s) {
    int n = s.length();
    int[] nextval = new int[n];
    
    int j = -1; // 前缀指针
    nextval[0] = -1; // 初始化第一个字符的 nextval 为 -1
    
    for (int i = 1; i < n; i++) {
        // 当当前字符不匹配时,回退前缀指针 j
        while (j >= 0 && s.charAt(i) != s.charAt(j + 1)) j = nextval[j]; 
        
        // 如果字符匹配,前缀长度加一
        if (s.charAt(i) == s.charAt(j + 1)) j++;

        // 若失配时,当前字符与 nextval[j] 指向的字符相同,则使用 nextval[j]
        if (i < n - 1 && s.charAt(i + 1) == s.charAt(j + 1)) 
            nextval[i] = nextval[j];
        else
            nextval[i] = j;

    }
    
    return nextval;
}

都看到这了,不妨一键三连再走吧!

🌈欢迎和毛毛张一起探讨和交流!
联系方式参见个人主页:
神马都会亿点点的毛毛张

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2039604.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【树的遍历】

题目 代码 #include<bits/stdc.h> using namespace std;const int N 40;int in[N], pos[N]; //中序、后序 int idx[N]; //中序的值->索引 unordered_map<int, int> l, r; //根节点的左、右树根节点 int n; int build(int il, int ir, int pl, int pr) {int ro…

【2】MySQL相关概念

一.数据库相关概念 二.MySQL数据库

软件接口测试有多重要?专业软件测试公司接口测试流程分享

在当今软件开发的各个阶段&#xff0c;软件接口测试无疑是一个极其重要的环节。接口测试主要针对软件系统与外部环境之间的交互部分&#xff0c;包括API、Web服务、中间件等。在现代软件架构中&#xff0c;接口的稳定性和一致性直接关系到系统的整体性能和用户体验。因此&#…

掌握电容器:详解其工作原理、分类、应用及测试技巧

电容器是一种不可或缺的基础元件。它们广泛应用于各种电路设计中&#xff0c;从简单的滤波电路到复杂的电源管理系统&#xff0c;无处不在。在此&#xff0c;道合顺将一一阐述其基本原理、分类、应用以及测试好坏方法&#xff0c;帮助读者们更清楚了解这一重要组件。 1、电容器…

如何利用YOLOv8训练自己的数据集 3种加载模型场景讲解

文章目录 前言1、环境搭建2、YOLOv8训练3、官网训练文档3.1、官网示例3.2、三种加载模型场景3.2.1、从YAML文件构建新模型3.2.2、从预训练权重构建模型3.2.3、从YAML文件构建新模型&#xff0c;并将预训练权重转移到新模型 4、总结5、目标检测系列文章 前言 本文主要介绍一下如…

linux 文件编程

标准IO和文件IO是计算机编程中用于处理输入/输出&#xff08;Input/Output&#xff0c;简称IO&#xff09;操作的两种不同方式&#xff0c;它们各自具有不同的特点和使用场景。 一、定义与特点 标准IO&#xff1a; 定义&#xff1a;标准IO通常指的是C语言提供的标准库中的IO…

第八季完美童模全球总冠军·韩嘉潞 破浪扬帆写就传奇

梦想的舞台上&#xff0c;星光璀璨&#xff0c;每一步都闪耀着坚持与努力的光芒。在这个盛夏&#xff0c;我们共同见证了一个关于勇气、才华与梦想的辉煌篇章——星光女孩韩嘉潞&#xff0c;在第八季完美童模的璀璨舞台上&#xff0c;以非凡的魅力与不懈的努力&#xff0c;勇夺…

奥运冠军郑钦文:荣耀与激励!

&#x1f396;️巴黎奥运的荣耀时刻&#xff0c;属于郑钦文&#xff01; 在巴黎奥运会的赛场上&#xff0c;郑钦文以无比的坚韧和卓越的技艺&#xff0c;一路过关斩将&#xff0c;最终登上了冠军的宝座&#xff01; 我们借助以下图片中的方法&#xff0c;将她在赛后视频发言中…

音频转换软件哪个好?试试这5款

潍坊新青年音乐节燃爆现场&#xff0c;音符跳跃间&#xff0c;想不想把最爱的现场Live一键转成手机铃声&#xff1f;别急&#xff0c;寻找免费电脑音频转换软件的你来对地方了&#xff01; 告别繁琐&#xff0c;5款专业级利器大放送&#xff0c;今天我来告诉你们&#xff1a;电…

阿里云-java调用短信服务,第三方接口的开启(傻瓜式教程)

第一步&#xff1a;在浏览器中&#xff0c;搜索阿里云 第二步&#xff1a;打开aly的主页 第三步&#xff1a;在最上方的导航栏中&#xff0c;找到云市场&#xff0c;注意不要点击&#xff0c;会自动有触发悬浮框出现&#xff0c;在悬浮框中找到 短信 第四步&#xff1a;点击 短…

Secure Coding in C and C ++ (三)关于语法与指针的感悟

上一篇文章中&#xff0c;我们讲了一些关于编译和链接以及基础的C知识。详情请见文章 SecureCoding in C and C&#xff08;二&#xff09; 本篇文章将从循环开始写起 1 循环 1. 1 for 先来个简单的例子&#xff1a; 打印hello world 五次&#xff1a; 很简单的吧 for循环的…

echarts学习:绘制地图

前言 经过之前一段时间的磨砺&#xff0c;我具备了基本的使用echarts绘制图表的能力。但是在最近这几个月里我接连遇到了几个棘手的任务&#xff0c;这大大的提升了我的echarts水平。其中我遇到的第一个高难度任务就是使用echarts绘制如下的地图&#xff1a; 简单的分析一下&a…

批量查询全国快递单号:高效追踪物流信息

在日常生活和工作中&#xff0c;我们经常会遇到需要查询多个快递单号物流信息的情况。如果手动逐一查询&#xff0c;不仅效率低下&#xff0c;而且容易出错。为了解决这个问题&#xff0c;我们可以借助固乔科技推出的【固乔快递查询助手】软件&#xff0c;轻松实现全国快递的批…

yolov5详解(一):网络结构

1. 完整的网络结构 以下是参考b站上作者以及yolov5官方代码画出的yolov5l v6.0版本的模型结构&#xff0c;v6.0版本的模型结构是目前yolov5版本的稳定版本&#xff0c;想必以后也不会有什么改变。l,m,n,s,x只是有些层以及输出通道数变化&#xff0c;整体架构是完全一样的&…

vue 项目中 使用vxe-grid 表格中给表格的表头设置特殊的格式 , 并且给指定的列文字设置颜色

项目场景&#xff1a; 相关背景&#xff1a; vue 项目中 使用vxe-grid 表格中给表格的表头设置特殊的格式&#xff0c;并为指定的列文字设置颜色 实现方案&#xff1a; 具体实现方法及步骤&#xff1a; 一、给表格的表头设置特殊的格式 实现方式一&#xff1a; :header-row-s…

WebDeveloper靶机复现

靶机设置 设置靶机为NAT模式 靶机IP发现 nmap 192.168.112.0/24 靶机ip为192.168.112.137 目录扫描 开放80端口&#xff0c;进行目录扫描 dirb 192.168.112.137 访问浏览器 目录拼接 拼接/ipdata 发现了一个流量包 在wireshark里面查看&#xff0c;发现wordpress的账户…

python提取b站视频的音频(提供源码

如果我想开一家咖啡厅&#xff0c;那么咖啡厅的音乐可得精挑细选&#xff01;又假设我非常喜欢o叔&#xff0c;而o叔只在b站弹钢琴&#xff0c;那这时候我就得想方设法把b站的视频转为音频咯&#xff01; 一、首先打开网页版bilibili&#xff0c;按F12&#xff1a; 二、刷新页面…

Java 空值与null 形参与实参学习

Java系列文章目录 文章目录 Java系列文章目录一、前言二、学习内容&#xff1a;三、问题描述四、解决方案&#xff1a;4.1 空值与null的区别4.1.1 空值&#xff08;Empty Value&#xff09;4.1.2 Null 4.2 形参与实参区别 五、总结&#xff1a;5.1 学习总结&#xff1a; 一、前…

智慧高速路三维可视化解决方案

项目背景 随着科技的快速发展&#xff0c;智慧高速公路的建设已成为交通领域的重要趋势。国家和相关部委陆续发布多项政策指导智慧公路建设&#xff0c;逐步制定相关建设标准规范&#xff0c;协助推动公路数字化、智能化升级。 方案简介 数字孪生高速公路解决方案是一种集成…