028.实现 strStr()

题意

给你两个字符串 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


 

对于这道题,我们很容易想到 Java字符串的indexOf()方法,我在二哥的 Java 进阶之路上也帮大家讲过这个方法的实现。

#String 类的 indexOf 方法

indexOf 方法用于查找一个子字符串在原字符串中第一次出现的位置,并返回该位置的索引。来看该方法的源码:

/** 查找字符数组 target 在字符数组 source 中第一次出现的位置。* sourceOffset 和 sourceCount 参数指定 source 数组中要搜索的范围,* targetOffset 和 targetCount 参数指定 target 数组中要搜索的范围,* fromIndex 参数指定开始搜索的位置。* 如果找到了 target 数组,则返回它在 source 数组中的位置索引(从0开始),* 否则返回-1。*/
static int indexOf(char[] source, int sourceOffset, int sourceCount,char[] target, int targetOffset, int targetCount,int fromIndex) {// 如果开始搜索的位置已经超出 source 数组的范围,则直接返回-1(如果 target 数组为空,则返回 sourceCount)if (fromIndex >= sourceCount) {return (targetCount == 0 ? sourceCount : -1);}// 如果开始搜索的位置小于0,则从0开始搜索if (fromIndex < 0) {fromIndex = 0;}// 如果 target 数组为空,则直接返回开始搜索的位置if (targetCount == 0) {return fromIndex;}// 查找 target 数组的第一个字符在 source 数组中的位置char first = target[targetOffset];int max = sourceOffset + (sourceCount - targetCount);// 循环查找 target 数组在 source 数组中的位置for (int i = sourceOffset + fromIndex; i <= max; i++) {/* Look for first character. */// 如果 source 数组中当前位置的字符不是 target 数组的第一个字符,则在 source 数组中继续查找 target 数组的第一个字符if (source[i] != first) {while (++i <= max && source[i] != first);}/* Found first character, now look at the rest of v2 */// 如果在 source 数组中找到了 target 数组的第一个字符,则继续查找 target 数组的剩余部分是否匹配if (i <= max) {int j = i + 1;int end = j + targetCount - 1;for (int k = targetOffset + 1; j < end && source[j]== target[k]; j++, k++);// 如果 target 数组全部匹配,则返回在 source 数组中的位置索引if (j == end) {/* Found whole string. */return i - sourceOffset;}}}// 没有找到 target 数组,则返回-1return -1;
}

那不就可以用此来解题了啊。

class Solution {public int strStr(String haystack, String needle) {int index = haystack.indexOf(needle);return index;}
}

来看效率:

JDK8 版本的方法签名是:


 

staticintindexOf(char[] source, int sourceOffset, int sourceCount,char[] target, int targetOffset, int targetCount,int fromIndex)


 

先来看参数:


 

  1. source:主字符串的字符数组。
  2. sourceOffset:主字符串的起始偏移量。
  3. sourceCount:主字符串中字符的总数。
  4. target:要查找的子字符串的字符数组。
  5. targetOffset:子字符串的起始偏移量。
  6. targetCount:子字符串中字符的总数。
  7. fromIndex:开始搜索的索引位置。

源码:

   static int indexOf(char[] source, int sourceOffset, int sourceCount,char[] target, int targetOffset, int targetCount,int fromIndex) {if (fromIndex >= sourceCount) {return (targetCount == 0 ? sourceCount : -1);}if (fromIndex < 0) {fromIndex = 0;}if (targetCount == 0) {return fromIndex;}char first = target[targetOffset];int max = sourceOffset + (sourceCount - targetCount);for (int i = sourceOffset + fromIndex; i <= max; i++) {/* Look for first character. */if (source[i] != first) {while (++i <= max && source[i] != first);}/* Found first character, now look at the rest of v2 */if (i <= max) {int j = i + 1;int end = j + targetCount - 1;for (int k = targetOffset + 1; j < end && source[j]== target[k]; j++, k++);if (j == end) {/* Found whole string. */return i - sourceOffset;}}}return -1;}

再来看逻辑流程


 

  1. 首先,检查fromIndex是否大于或等于sourceCount。如果是,且targetCount为 0,则返回sourceCount;否则返回-1。
  2. 如果fromIndex小于 0,它被设置为 0。
  3. 如果targetCount为 0,则直接返回fromIndex,因为空字符串被认为存在于任何位置。
  4. 然后,计算最大搜索索引max,这是为了确保搜索时target能够完全位于source中。
  5. 接下来,遍历source数组,从sourceOffset + fromIndex开始,直到max,查找与target数组中第一个字符匹配的字符。
  6. 一旦找到第一个匹配的字符,就在source中从这个位置开始,尝试匹配整个target数组。
  7. 如果所有后续字符都匹配,就返回当前的索引(调整过的,即i - sourceOffset),因为这表示找到了完整的子字符串。
  8. 如果遍历完成后未找到匹配的子字符串,则返回-1。


 

这种实现方式在处理大字符串时效率不如KMP(Knuth-Morris-Pratt)算法,但 JDK 选择了这种更易于理解和实现的方法,足以处理大多数常见的情况。


 

所以,我们可以按照这个思路来实现我们的strStr()方法。

class Solution {public int strStr(String haystack, String needle) {// 获取主字符串和子字符串的长度int sourceCount = haystack.length();int targetCount = needle.length();// 如果子字符串为空,则根据题目要求返回0if (targetCount == 0) {return 0;}// 获取子字符串的第一个字符,用于后续匹配的起点char first = needle.charAt(0);// 计算搜索的最大起始位置,确保子字符串能够完全位于主字符串中int max = sourceCount - targetCount;// 遍历主字符串for (int i = 0; i <= max; i++) {// 寻找与子字符串第一个字符匹配的字符if (haystack.charAt(i) != first) {// 如果当前字符不匹配,继续向后搜索直到找到匹配的字符或达到最大索引while (++i <= max && haystack.charAt(i) != first);}// 找到第一个字符后,检查剩余的部分是否也匹配if (i <= max) {int j = i + 1; // 设置匹配的下一个字符的索引int end = j + targetCount - 1; // 计算子字符串在主字符串中的结束位置for (int k = 1; j < end && haystack.charAt(j) == needle.charAt(k); j++, k++);// 如果整个子字符串都匹配了,返回其在主字符串中的起始索引if (j == end) {return i;}}}// 如果遍历完成后没有找到匹配的子字符串,返回-1return -1;}
}


如果觉得上面的代码有点复杂,我们可以稍微简化一下:

class Solution {public int strStr(String haystack, String needle) {// 如果 needle 是空字符串,则按照题目要求返回 0if (needle.isEmpty()) {return 0;}// 获取两个字符串的长度int n = haystack.length();int m = needle.length();// 遍历 haystack 字符串for (int i = 0; i <= n - m; i++) {// 从 haystack 的第 i 个字符开始,取一个长度为 m 的子字符串String subStr = haystack.substring(i, i + m);// 比较这个子字符串与 needle 是否相等if (subStr.equals(needle)) {return i; // 如果相等,则返回当前的起始位置}}return -1; // 如果遍历结束都没有找到匹配的位置,则返回 -1}
}

这个方法就非常好懂了,对吧,我们只需要遍历主字符串,然后取出一个长度为子字符串的子串,然后比较两个子串是否相等,如果相等,就返回当前的起始位置。


 

利用了字符串的 substring() 方法和 equals() 方法,来看一下题解效率:

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2023版brupsuite专业破解安装

安装教程&#xff0c;分两部分&#xff1a; 1、安装java环境、参考链接JAVA安装配置----最详细的教程&#xff08;测试木头人&#xff09;_java安装教程详细-CSDN博客 2、安装2023.4版本brupsuite&#xff1a;参考链接 2023最新版—Brup_Suite安装配置----最详细的教程&…

语音网关有哪些?

语音网关是一种网络设备&#xff0c;它使得通过传统的电话网络&#xff08;如公共交换电话网络&#xff0c;PSTN&#xff09;和现代的数据网络&#xff08;如互联网或私有数据网络&#xff09;进行的语音通信成为可能。语音网关的主要作用是在模拟或数字电话信号与数据网络的数…

算法学习笔记(2)-前缀和

##前缀和 指的是某序列的前n项和&#xff0c;在数学上我们可以理解称为数列的前n项和。前缀和是一种预处理&#xff0c;用于降低查询的时间复杂度。 ##一维前缀和 有一个一维数组x和该数组的前缀和数组y&#xff0c;则x和y具有以下关系&#xff1a; #python代码示例 #关系&am…

1.前端环境搭建

1.安装nodejs 因为我们开发Vue项目需要使用npm命令来创建和启动&#xff0c;安装node.js是为了获得这个命令&#xff0c;目前和使用node.js无关 下载地址&#xff1a;http://nodejs.cn/download/ 下载完之后安装&#xff0c;通过cmd查看是否安装成功 node --version2.创建项目…

IDEA使用技巧2—发布web项目

作者&#xff1a;私语茶馆 1.War包类型 发布Web项目有两种模式&#xff1a;war和war exploded&#xff0c; war模式&#xff1a;将WEB工程以包的形式上传到服务器 &#xff1b;war exploded模式&#xff1a;将WEB工程以当前文件夹的位置关系上传到服务器&#xff1b; war ex…

C语言例题37、输入三组数字,按照从小到大的顺序排列输出

#include<stdio.h>int main() {int num[3];printf("请输入3组数字&#xff1a;");for (int i 0; i < 3; i)scanf("%d", &num[i]);for (int i 0; i < 2; i) { //每次选出最小值放在数组前面for (int j i 1; j < 3; j) {if (num[j] …

示例六、湿敏传感器

通过以下几个示例来具体展开学习,了解湿敏传感器原理及特性&#xff0c;学习湿敏传感器的应用&#xff1a; 示例六、湿敏传感器 一、基本原理&#xff1a;随着人们生活水平的不断提高&#xff0c;湿度监控逐步提到议事日程上。由于北方地区秋冬季干燥&#xff0c;需要控制室内…

【C++】string类的使用③(修改器Modifiers || 非成员函数重载Non-member function overloads)

&#x1f525;个人主页&#xff1a; Forcible Bug Maker &#x1f525;专栏&#xff1a; STL || C 目录 前言&#x1f525;修改器&#xff08;Modifiers&#xff09;**operator**appendpush_back和pop_backassigninserterasereplaceswap &#x1f525;非成员函数重载&#xff…

新能源汽车动力电池浸没式冷却方案介绍与未来趋势

前言 新能源汽车的兴起标志着汽车工业的一次革命&#xff0c;其中动力电池的设计与性能成为了关键。浸没式冷却方案作为一种新兴的技术&#xff0c;为动力电池系统提供了有效的散热解决方案&#xff0c;其在未来的发展趋势备受关注。 一 动力电池浸没式冷却方案介绍 首先&am…

Python中tkinter编程入门3

在使用tkinter创建了窗口之后&#xff0c;可以将一些控件“放置”到窗口中。这些控件包括标签、按键以及输入框等。 1 在窗口中“放置”标签 在窗口中“放置”标签主要有两个步骤&#xff0c;一是创建标签控件&#xff0c;二是将创建好的标签“放置”到窗口上。 1.1 创建标签…

Linux-线程概念

1. 线程概念 线程&#xff1a;轻量级进程&#xff0c;在进程内部执行&#xff0c;是OS调度的基本单位&#xff1b;进程内部线程共用同一个地址空间&#xff0c;同一个页表&#xff0c;以及内存中的代码和数据&#xff0c;这些资源对于线程来说都是共享的资源 进程&#xff1a;…

高效视频剪辑:视频批量调色,如何利用色调调整提升效率

在视频剪辑的后期处理中&#xff0c;调色是一个至关重要的环节。它不仅能够改变视频的整体氛围和风格&#xff0c;还能够突出视频的重点&#xff0c;增强观众的视觉体验。然而&#xff0c;对于大量的视频素材进行逐个调色处理&#xff0c;无疑会耗费大量的时间和精力。我们可以…