代码随想录【Day09】|28. 找出字符串中第一个匹配项的下标、459. 重复的子字符串、《字符串总结》

news2024/11/26 22:38:59

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

题目链接

题目描述:
实现 strStr() 函数。

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

示例 1: 输入: haystack = “hello”, needle = “ll” 输出: 2

示例 2: 输入: haystack = “aaaaa”, needle = “bba” 输出: -1

说明: 当 needle 是空字符串时,我们应当返回什么值呢?这是一个在面试中很好的问题。 对于本题而言,当 needle 是空字符串时我们应当返回 0 。

思路:
这题考查KMP算法
需要了解一些概念:

  • KMP名字由来?用来做什么的?
  • 什么是文本串?
  • 什么是模式串?
  • 什么是前缀表?如何构建?

理解前缀和后缀

字符串的前缀
是指不包含最后一个字符的所有以第一个字符开头的连续子串;
字符串的后缀
是指不包含第一个字符的所有以最后一个字符结尾的连续子串。

精髓 —— 找最长相等的 前缀 和 后缀,匹配失败的位置是后缀子串的后面,那么我们找到与其相同的 前缀 的后面重新匹配就可以了!
(前缀表数组中每个位置记录的就是当前子串中最长相等的前后缀长度)

next数组就是前缀表,有的会将数值统一减一,这涉及到具体实现上的习惯。

构造next数组(针对模式串计算):

  1. 初始化
  2. 处理前后缀不相同的情况
  3. 处理前后缀相同的情况

注意下标回退时,可能会连续回退,要保证其next取下标的时候不能越界

动画演示
以模式串aabaaf为例,手撕其对应next数组的构建过程↓
在这里插入图片描述

难点:
经典KMP,必须掌握。

文本串长度——n,模式串长度——m
时间复杂度:O(n+m)
空间复杂度:O(m)

class Solution {
	//构造next数组(针对模式串)
    public void getNext(int[] next, String s) {
        int j = -1; //统一减一
        next[0] = j;
        for (int i = 1; i < s.length(); i++) {
            while (j >= 0 && s.charAt(i) != s.charAt(j+1)) {
                j = next[j]; //回退
            }
            if (s.charAt(i) == s.charAt(j+1)) {
                j++; //更新当前子串最长公共前后缀长度
            }
            next[i] = j; //更新next数组
        }
    }
	//字符串模式匹配
    public int strStr(String haystack, String needle) {
        int[] next = new int[needle.length()];
        getNext(next, needle);
        int j = -1;
        for (int i = 0; i < haystack.length(); i++) { //从0开始
            while (j >= 0 && haystack.charAt(i) != needle.charAt(j+1)) {
                j = next[j];
            }
            if (haystack.charAt(i) == needle.charAt(j+1)) {
                j++;
            }
            if (j == needle.length()-1) {
                return i-needle.length()+1;
            }
        }
        return -1;
    }
}

next数组统一不减一

class Solution {
    //构造next数组(针对模式串)
    private void getNext(int[] next, String s) {
        int j = 0; //统一不减一
        next[0] = 0;
        for (int i = 1; i < s.length(); i++) {
            while (j > 0 && s.charAt(j) != s.charAt(i)) 
                j = next[j - 1]; //回退
            if (s.charAt(j) == s.charAt(i)) 
                j++; //更新当前子串最长公共前后缀长度
            next[i] = j; //更新next数组
        }
    }
    public int strStr(String haystack, String needle) {
        int[] next = new int[needle.length()];
        getNext(next, needle);
        int j = 0;
        for (int i = 0; i < haystack.length(); i++) { //从0开始
            while (j > 0 && needle.charAt(j) != haystack.charAt(i)) 
                j = next[j - 1];
            if (needle.charAt(j) == haystack.charAt(i)) 
                j++;
            if (j == needle.length()) 
                return i - needle.length() + 1;
        }
        return -1;
    }
}

时长:
40min

收获:
熟悉相关概念:文本串、模式串、前缀表、最长公共(相等)前后缀
掌握next数组的构造过程


459. 重复的子字符串

题目链接

题目描述:
给定一个非空的字符串,判断它是否可以由它的一个子串重复多次构成。给定的字符串只含有小写英文字母,并且长度不超过10000。

示例 1:
输入: “abab”
输出: True
解释: 可由子字符串 “ab” 重复两次构成。

示例 2:
输入: “aba”
输出: False

示例 3:
输入: “abcabcabcabc”
输出: True
解释: 可由子字符串 “abc” 重复四次构成。 (或者子字符串 “abcabc” 重复两次构成。)

思路1:
因为题中模式串没有给出,所以模式串是变化的

  1. 由当前下标作为结尾截取模式串
  2. 遍历剩余文本串看看是否匹配
  3. 如果不匹配,回到1,更新下标
  4. 如果匹配,若已经遍历到结尾,满足题目要求!;否则,继续遍历剩余文本串

难点:
模式串是未知的

时间复杂度:O(n)
空间复杂度:O(n)

class Solution {
    public boolean repeatedSubstringPattern(String s) {
        String pattern = "";
        for (int i = 0; i < s.length()/2; i++) {
            pattern = s.substring(0, i + 1);

            if (s.length() - pattern.length() < 0) { //剪枝:如果字符串剩余长度还没模式串长,那没有重复的模式串
                return false;
            }

            int j = i + pattern.length();
            while (j < s.length()) {
                String substring = s.substring(j-pattern.length()+1, j + 1);
                if (!substring.equals(pattern)) {
                    break;
                }
                if (j == s.length()-1) { //如果在检查剩余字符串,直到最后的位置都没break,满足!
                    return true;
                }
                j += pattern.length(); //文本串下标更新:每次跳跃当前模式串的长度
            }
        }
        return false;
    }
}

思路2:
KMP
累了累了,回头再研究。。。

时长:
30min

收获:


字符串总结

复杂的字符串题目非常考验对代码的掌控能力。
下面小结一下Java字符串中常用内容:

String常用方法
 int length():
返回字符串的长度: return value.length
 char charAt(int index):
返回某索引处的字符return value[index]
 boolean isEmpty():
判断是否是空字符串:return value.length == 0
 String toLowerCase():
使用默认语言环境,将 String 中的所有字符转换为小写
 String toUpperCase():
使用默认语言环境,将 String 中的所有字符转换为大写
 String trim():
返回字符串的副本,忽略前导空白和尾部空白
 boolean equals(Object obj):
比较字符串的内容是否相同
 boolean equalsIgnoreCase(String anotherString):
与equals方法类似,忽略大小写
 String concat(String str):
将指定字符串连接到此字符串的结尾。 等价于用“+”
 int compareTo(String anotherString):
比较两个字符串的大小
 String substring(int beginIndex):
返回一个新的字符串,它是此字符串的从 beginIndex开始截取到最后的一个子字符串。
 String substring(int beginIndex, int endIndex) :
返回一个新字符串,它是此字符串从beginIndex开始截取到endIndex(不包含)的一个子字符串。
 boolean endsWith(String suffix):
测试此字符串是否以指定的后缀结束
 boolean startsWith(String prefix):
测试此字符串是否以指定的前缀开始
 boolean startsWith(String prefix, int toffset):测试此字符串从指定索引开始的 子字符串是否以指定前缀开始
 boolean contains(CharSequence s):
当且仅当此字符串包含指定的 char 值序列时,返回 true
 int indexOf(String str):
返回指定子字符串在此字符串中第一次出现处的索引
 int indexOf(String str, int fromIndex):
返回指定子字符串在此字符串中第一次出现处的索引,从指定的索引开始
 int lastIndexOf(String str):
返回指定子字符串在此字符串中最右边出现处的索引
 int lastIndexOf(String str, int fromIndex):
返回指定子字符串在此字符串中最后 一次出现处的索引,从指定的索引开始反向搜索 注:indexOf和lastIndexOf方法如果未找到都是返回-1
 String replace(char oldChar, char newChar):
返回一个新的字符串,它是通过用 newChar 替换此字符串中出现的所有 oldChar 得到的。
 String replace(CharSequence target, CharSequence replacement):
使用指定的字面值替换序列替换此字符串所有匹配字面值目标序列的子字符串。
 String replaceAll(String regex, String replacement):
使用给定的 replacement 替换此字符串所有匹配给定的正则表达式的子字符串。
 String replaceFirst(String regex, String replacement):
使用给定的 replacement 替换此字符串匹配给定的正则表达式的第一个子字符串。
 boolean matches(String regex):
告知此字符串是否匹配给定的正则表达式。
 String[] split(String regex):
根据给定正则表达式的匹配拆分此字符串。
 String[] split(String regex, int limit):
根据匹配给定的正则表达式来拆分此字符串,最多不超过limit个,如果超过了,剩下的全部都放到最后一个元素中。

String与基本数据类型转换
字符串 → 基本数据类型、包装类
Integer包装类的public static int parseInt(String s):可以将由“数字”字符组成的字符串转换为整型。
类似地,使用java.lang包中的Byte、Short、Long、Float、Double类调相应的类方法可以将由“数字”字符组成的字符串,转化为相应的基本数据类型。

基本数据类型、包装类 → 字符串
调用String类的public String valueOf(int n)可将int型转换为字符串
相应的valueOf(byte b)、valueOf(long l)、valueOf(float f)、valueOf(double d)、valueOf(boolean b)可由参数的相应类型到字符串的转换

String与字符数组转换
字符数组 → 字符串
String 类的构造器:String(char[]) 和 String(char[], int offset, int length) 分别用字符数组中的全部字符和部分字符创建字符串对象。
字符串 → 字符数组
 public char[] toCharArray():将字符串中的全部字符存放在一个字符数组中的方法。
 public void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin):提供了将指定索引范围内的字符串存放到数组中的方法。

String、StringBuilder、StringBuffer
StringBuffer类有三个构造器:
StringBuffer():初始容量为16的字符串缓冲区
StringBuffer(int size):构造指定容量的字符串缓冲区
StringBuffer(String str):将内容初始化为指定字符串内容
常用方法:
StringBuffer append(xxx):提供了很多的append()方法,用于进行字符串拼接
StringBuffer delete(int start,int end):删除指定位置的内容
StringBuffer replace(int start, int end, String str):把[start,end)位置替换为str
StringBuffer insert(int offset, xxx):在指定位置插入xxx
StringBuffer reverse() :把当前字符序列逆转

StringBuilder 和 StringBuffer 非常类似,均代表可变的字符序列,而且提供相关功能的方法也一样
面试题:对比String、StringBuffer、StringBuilder
String(JDK1.0):不可变字符序列
StringBuffer(JDK1.0):可变字符序列、效率低、线程安全
StringBuilder(JDK 5.0):可变字符序列、效率高、线程不安全
注意:作为参数传递的话,方法内部String不会改变其值,StringBuffer和StringBuilder 会改变其值。

最后:
双指针法是字符串处理的常客。

双指针法在数组,链表和字符串中很常用。
双指针法总结

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

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

相关文章

计算机图形学:改进的中点BH算法

作者&#xff1a;非妃是公主 专栏&#xff1a;《计算机图形学》 博客地址&#xff1a;https://blog.csdn.net/myf_666 个性签&#xff1a;顺境不惰&#xff0c;逆境不馁&#xff0c;以心制境&#xff0c;万事可成。——曾国藩 文章目录专栏推荐专栏系列文章序一、改进缘由二、…

qt连接mysql,自编译生成驱动文件

CMakeninja编译qt所需的mysql驱动文件 想用qt连接mysql数据库&#xff0c;但是在qt6.0版本之后都不自带驱动需要自己编译&#xff0c;过程中由于不熟悉cmake以及ninja&#xff0c;踩了一百个坑&#xff0c;简单记录一下。 写在前面 csdn上也有很多大佬写得用cmake-gui来编译…

代码随想录算法训练营第43天DP动态规划62不同路径63 不同路径2

文章目录LeetCode 62不同路径题目讲解思路LeetCode 63 不同路径ii题目讲解思路小结LeetCode 62不同路径 题目讲解 思路 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角&#xff08;在下图中标记为 “Finish” &#xff09;。 根据题意来看机器人只能进行向右…

单链表的基本操作

此代码不可运行&#xff0c;含伪代码。一、 定义数据域typedef struct{ char num[8];char name[8];int score;}ElemType;二、 定义一个链表typedef struct LNode{ElemType data; //链表中结点的数据域 struct Lnode *next; //为指向下一个结点的指针域&#xff0c;并且所指向的…

物理师知识大杂烩|CT模拟机质量控制指南

引言 放射治疗 CT 模拟机&#xff08;computed tomography simulators, CT-Sim&#xff09;由带有平板床面的 CT 扫描仪、用于患者定位与体表标记的外部激光系统、CT 模拟软件以及各种硬拷贝输出设备组成。CT 模拟机为放射治疗计划设计提供了患者肿瘤、正常组织与危及器官的影…

TMDSEVM6657LS评估板恢复出厂默认状态

TMDSEVM6657LS评估板恢复出厂默认状态 前言 TMDSEVM6657LS评估板特别适用于DSP开发的初学者&#xff0c;但有时候拿到手的开发板几经流转&#xff0c;被别人修改过&#xff0c;也可能自己烧录过程出错&#xff0c;导致开发板的状态未知等原因&#xff0c;需要恢复到出厂默认状…

Django的安装及创建项目

Django的安装及创建demo项目 打开PyCharm&#xff0c;选择创建Django项目勾选使用Virtualenv创建虚拟环境&#xff0c;并选择合适的Python编译器版本即可。 注&#xff1a;如果因为其他原因&#xff08;没有关闭vpn等&#xff09;也可以在PyCharm提供的terminal终端&#xf…

uni-app低成本封装一个取色器组件

在uni-ui中找不到对应的工具 后面想想也是 移动端取色干什么&#xff1f; 没办法 也挂不住特殊需求 因为去应用市场下载 这总东西 又不是很有必要 那么 下面这个组件或许能解决您的烦恼 <template><view class"content"><view class"dialog&…

侯捷C++系统工程师

前言我相信对于每一个学习C的同学和从业者来说&#xff0c;台湾著名学者侯捷老师的C系列都是不可错过的好视频。侯捷老师在网上已有五门课&#xff0c;分别是&#xff1a;C面向对象开发、STL标准库与泛型编程、C新标准C1&14、C内存管理机制以及C Startup揭秘讲师介绍侯捷老…

python基于django+vue的高铁地铁火车订票管理系统

目录 1 绪论 1 1.1课题背景 1 1.2课题研究现状 1 1.3初步设计方法与实施方案 2 1.4本文研究内容 2 2 系统开发环境 4 2.1 使用工具简介 4 2.2 环境配置 4 2.4 MySQL数据库 5 2.5 框架介绍 5 3 系统分析 6 3.1系统可行性分析 6 3.1.1经济可行性 6 3.1.2技术可行性 6 3.1.3运行可…

pandas——DataFrame基本操作(二)【建议收藏】

pandas——DataFrame基本操作&#xff08;二&#xff09; 文章目录pandas——DataFrame基本操作&#xff08;二&#xff09;一、实验目的二、实验原理三、实验环境四、实验内容五、实验步骤1.修改数据2.缺失值3.合并1.concat合并2.使用append方法合并3.使用merge进行合并4.使用…

为什么实时ERP系统是唯一的出路?

长期以来&#xff0c;企业主不得不等待数天&#xff0c;有时甚至数周&#xff0c;才能获得财务和运营结果。今天&#xff0c;尤其是在我们可以使用高速计算机和实时技术的情况下&#xff0c;这绝不应该成为可接受的标准。 然而&#xff0c;太多的大牌ERP系统仍然使用批量处理…

2023年网络安全比赛--Web综合渗透测试中职组(超详细)

一、竞赛时间 180分钟 共计3小时 二、竞赛阶段 1.通过URL访问http://靶机IP/1,对该页面进行渗透测试,将完成后返回的结果内容作为FLAG值提交; 2.通过URL访问http://靶机IP/2,对该页面进行渗透测试,将完成后返回的结果内容作为FLAG值提交; 3.通过URL访问http://靶机IP/3,对…

CDN绕过技术总汇

注 本文首发于合天网安实验室 首发链接&#xff1a;https://mp.weixin.qq.com/s/9oeUpFUZ_0FUu6YAhQGuAg 近日HVV培训以及面试&#xff0c;有人问了CDN该如何绕过找到目标真实IP&#xff0c;这向来是个老生常谈的问题&#xff0c;而且网上大多都有&#xff0c;但是有些不够全面…

中国网站安全形式风险报告

声明 本文是学习2017中国网站安全形势分析报告. 而整理的学习笔记,分享出来希望更多人受益,如果存在侵权请及时联系我们 网站漏洞检测分析 网站漏洞的整体形势可以从两个角度分析&#xff1a;一是网站安全检测的自动扫描结果统计&#xff0c;二是网站被报告漏洞情况的统计。…

FreeRTOS队列 | FreeRTOS九

目录 说明&#xff1a; 一、队列简介 1.1、什么是队列 1.2、队列的优势 1.3、队列实现功能 1.4、队列使用了解 1.5、队列特点 1.6、队列阻塞处理 1.7、队列出队入队过程 二、队列结构体 2.1、结构体了解 2.2、共同体了解 2.3、队列结构体存储区 三、队列API函数 …

nacos配置中心搭建

网站每次更新版本都有短暂暂停&#xff0c;影响用户使用&#xff0c;返回经常不可用&#xff0c;需要改进 需要实现高可用&#xff0c;搭建负载均衡&#xff0c;实现jenkinsnacos不停机部署 nacos搭建预备环境准备 64 bit OS&#xff0c;支持 Linux/Unix/Mac/Windows&#x…

vue2.0项目第一部分

论坛项目后端管理系统服务器地址&#xff1a;http://172.16.11.18:9090swagger地址&#xff1a;http://172.16.11.18:9090/doc.html前端h5地址&#xff1a;http://172.16.11.18:9099/h5/#/前端管理系统地址&#xff1a;http://172.16.11.18:9099/admin/#/搭建项目vue create . …

JavaScript 变量提升

文章目录JavaScript 变量提升JavaScript 初始化不会提升在头部声明你的变量JavaScript 变量提升 JavaScript 中&#xff0c;函数及变量的声明都将被提升到函数的最顶部。 JavaScript 中&#xff0c;变量可以在使用后声明&#xff0c;也就是变量可以先使用再声明。 以下两个实…

前端面试题汇总

一&#xff1a;JavaScript 1、闭包是什么&#xff1f;利弊&#xff1f;如何解决弊端&#xff1f; 闭包是什么&#xff1a;JS中内层函数可以访问外层函数的变量&#xff0c;外层函数无法操作内存函数的变量的特性。我们把这个特性称作闭包。 闭包的好处&#xff1a; 隔离作用…