leetcode【字符串—简单】459.重复的子字符串

2023-10-20 23:59

本文主要是介绍leetcode【字符串—简单】459.重复的子字符串,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • 前言
  • 题目
  • 题解
  • 正文
    • NO1:整除比较法(初始思路)
    • NO2:KMP解决(核心,重点掌握)
    • NO3:超级整除法(参考大佬)
    • NO4、超简洁解法(看看就好)
  • 参考文章

前言

哈喽,我是长路,目前刚刚大三,方向是后端也偶尔捣鼓下前端,现在的主语言是Java。之前一大段时间都是在学习web开发的一些技术,就很久没有进行类似于数据结构、算法之类的学习与刷题,打算这段时间拾起来好好学一学、搞一搞。

这段时间也是机缘巧合看到草帽路飞的博客,加了自学群,正巧看到博主组织在群里组织了leetcode刷题打卡活动,我也就参与进来,为期一个月,打算坚持每天都花一些时间做一些题目,并通过博客的方式来进行记录。

目前跟着一个Github仓库刷题(leetcode):代码随想录leetcode刷题,当前为链表专题。



题目

题目来源leetcode

leetcode地址:459. 重复的子字符串,难度:简单。

题目描述(摘自leetcode):

给定一个非空的字符串,判断它是否可以由它的一个子串重复多次构成。给定的字符串只含有小写英文字母,并且长度不超过10000。示例 1:
输入: "abab"
输出: True
解释: 可由子字符串 "ab" 重复两次构成。示例 2:
输入: "aba"
输出: False示例 3:
输入: "abcabcabcabc"
输出: True
解释: 可由子字符串 "abc" 重复四次构成。 (或者子字符串 "abcabc" 重复两次构成。)

本地调试代码:

class Solution {public boolean repeatedSubstringPattern(String s) {...}public static void main(String[] args) {System.out.println(new Solution().repeatedSubstringPattern("aba"));}}


题解

正文

NO1:整除比较法(初始思路)

思路: 先自己想思路,有了思路直接code就行,当前提交没有看题解。

核心点:一个子串重复多次构成、只含有小写英文字母、长度不超过10000
思路:
1、确定每次重复的个数,这是我们能够确定的。例如"abababab",长度为8。那么每次重复个数情况有1、2、4。(for循环模一下即可判定)
2、直到重复个数之后就好办了,重新开个for循环从指定位置开始指定长度比较就ok,一旦一组比较下来都相同直接返回true,否则进行其他重复个数情况二次比较!

代码

public boolean repeatedSubstringPattern(String s) {String subStr = "";for (int i = 1; i < s.length(); i++) {//每i个数能够成对出现if(s.length() % i == 0){subStr = s.substring(0,i);int j = i;for (; j < s.length(); j+=i) {if(!Objects.equals(subStr,s.substring(j,j+i))){break;}}if(j == s.length()){return true;}}}return false;
}

image-20211031202208437

同样与这个思路一致,将直接取两个子串方式改为取两个指针来从左到右进行比较,看下是否有时间上的优化:

  • 注释的内容表示被替换了
public boolean repeatedSubstringPattern(String s) {//        String subStr = "";for (int i = 1; i < s.length(); i++) {if(s.length() % i == 0){//                subStr = s.substring(0,i);int j = i;for (; j < s.length(); j+=i) {//左右指针比较//                    if(!Objects.equals(subStr,s.substring(j,j+i))){//                        break;//                    }/*******直接取子串=>左右连续对比*******/int subStrCur = 0;int jCur = j;while(subStrCur != i){if(s.charAt(subStrCur) != s.charAt(jCur)){break;}subStrCur++;jCur++;}if(subStrCur != i){break;}/**************/}if(j == s.length()){return true;}}}return false;
}

image-20211101140019454

效果感觉不咋地,反而比我们使用subString()取字符串来的效率高,现在去看下其他人题解。



NO2:KMP解决(核心,重点掌握)

思路:利用KMP算法求得next数组,接着通过next数组最后一个元素的指向的最长重复前缀位置来进行判断是否当前字符串是否为重复的子字符串。

举例:
例1:s="abababab"  next[] = [-1, -1, 0, 1, 2, 3, 4, 5]next数组最后一个位置为5,指向原字符串中的倒数第三个,使用原字符串长度减去该位置-1,8-5-1=2,2就指的是对应子串的长度,接着使用字符串长度进行%,若是=0,表示其为重复子串。公式为:s.length() % (s.length() - targetPos - 1) == 0例2:s="ababcddc" next=[-1, -1, 0, 1, -1, -1, -1, -1]最后位置为-1,直接判定没有重复字符串。例3:s="ababcdab" next[] = [-1, -1, 0, 1, -1, -1, 0, 1]最后位置为1,同理代入,8%(8-1-1)=2,没有整%,所以直接判断没有

代码:时间复杂度O(n)

public int getNext(String s) {//KMP求得next数组        int next[] = new int[s.length()];int j = -1;next[0] = -1;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;}return next[s.length() - 1];
}public boolean repeatedSubstringPattern(String s) {//使用KMP取到最后一个元素重复元素前缀位置int targetPos = getNext(s);if (targetPos == -1) {return false;}if (s.length() % (s.length() - targetPos - 1) == 0) {return true;}return false;
}

image-20211101143900259



NO3:超级整除法(参考大佬)

使用KMP最后的执行耗时才击败了62%的人,接着就去看了看大佬的代码,真的是特别特别巧妙!

思路:相对于NO1的整除法,中间有很多没必要二次比较的情况,并且我是从小数重复串进行一一比对的,这里使用大数重复串比较,并且省去了一些没必要重复比较的情况。

假设某个字符串长度为8,按照正常思路顺序,先取最长重复串长度为4个4个比较、失败取2个2个、失败再取1个1个。
其实后面的两次就是没有必要的,我们举个例子:"abababac"①abab abac  (失败)②ab ab ab ac (失败)③a b a b a b b a c (失败)
仔细看第二步,假设它是重复串组成ab ab ab ab,那么就必然就有abab abab判断成功,那么①失败,下面的②③比较自然没有必要了。其规律就可以找到凡是某个最大子串匹配失败,那么其整除的情况(也就是②③)直接可以省略掉。上面说明了没必要重复比较的情况,下面再举一个长度为6的例子:"ababab"①aba bab (失败)②ab ab ab (成功)
对于该种情况,第②步是不用被省略的,因为第一组最大重复数量为3,其并不能整除2,那么对重复长度为2的自然会进行一一比较,这里就有一个问题,我们该如何进行比较?上面长度为6的有三组,难道要一个一个进行比?从大佬的代码中我又看到了解答,所有任意情况只要比较1次即可,对于②中取出abab abab这两个,刚开始我也贼蒙蔽,不过之后就感叹其妙的地方了。
重复长度2,第一组[0,6-2-1]=>[0,3] 第二组[2,6-1]=>[2-5],假设三组子字符串都先相同,那么任意两组之和也必然相同,借助这个要点,我们即可将多组比较化为2组比出结果。

代码

public boolean repeatedSubstringPattern2(String s) {int len = s.length();int parts = 2;//从2开始,之后取子串len/2、len/3,保证子串从最大长度开始进行比较重复int noRepeatLen = len;while (noRepeatLen > 1) {if (noRepeatLen % parts == 0) {int k = len / parts;//子串长度//取出两组进行比较if (Objects.equals(s.substring(0, len - k), s.substring(k))) {return true;}//去除重复的整除情况,在除数上进行操作noRepeatLen /= parts;while (noRepeatLen % parts == 0) {noRepeatLen /= parts;}}parts++;}return false;
}

image-20211101182730440



NO4、超简洁解法(看看就好)

好家伙,两行解决?还是很妙的。举两个例子就可以看懂了。

思路

① s="abac" 不重复情况  "ababca"s+s = "abacabac",去头去尾"bacaba"
② s="abab"s+s = "abababab",去头去尾"bababa" √
③ s="aaaa"s+s = "aaaaaaaa",去头去尾"aaaaaa" √这种方式很巧妙,通过拼接方式去头去尾看其中是否存在原字符串。若是有重复的必然拼接中有对应重复的!

代码

public boolean repeatedSubstringPattern(String s) {String str = s + s;return str.substring(1, str.length() - 1).contains(s);
}

image-20211101185001905



参考文章

[1]. leetcode题解

[2]. 代码随想录—459.重复的子字符串


我是长路,感谢你的耐心阅读。如有问题请指出,我会积极采纳!
欢迎关注我的公众号【长路Java】,分享Java学习文章及相关资料
Q群:851968786 我们可以一起探讨学习
注明:转载可,需要附带上文章链接

这篇关于leetcode【字符串—简单】459.重复的子字符串的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/250530

相关文章

Springboot3+将ID转为JSON字符串的详细配置方案

《Springboot3+将ID转为JSON字符串的详细配置方案》:本文主要介绍纯后端实现Long/BigIntegerID转为JSON字符串的详细配置方案,s基于SpringBoot3+和Spr... 目录1. 添加依赖2. 全局 Jackson 配置3. 精准控制(可选)4. OpenAPI (Spri

基于Python实现一个简单的题库与在线考试系统

《基于Python实现一个简单的题库与在线考试系统》在当今信息化教育时代,在线学习与考试系统已成为教育技术领域的重要组成部分,本文就来介绍一下如何使用Python和PyQt5框架开发一个名为白泽题库系... 目录概述功能特点界面展示系统架构设计类结构图Excel题库填写格式模板题库题目填写格式表核心数据结构

C#之List集合去重复对象的实现方法

《C#之List集合去重复对象的实现方法》:本文主要介绍C#之List集合去重复对象的实现方法,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录C# List集合去重复对象方法1、测试数据2、测试数据3、知识点补充总结C# List集合去重复对象方法1、测试数据

使用Python实现base64字符串与图片互转的详细步骤

《使用Python实现base64字符串与图片互转的详细步骤》要将一个Base64编码的字符串转换为图片文件并保存下来,可以使用Python的base64模块来实现,这一过程包括解码Base64字符串... 目录1. 图片编码为 Base64 字符串2. Base64 字符串解码为图片文件3. 示例使用注意

C/C++ chrono简单使用场景示例详解

《C/C++chrono简单使用场景示例详解》:本文主要介绍C/C++chrono简单使用场景示例详解,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友... 目录chrono使用场景举例1 输出格式化字符串chrono使用场景China编程举例1 输出格式化字符串示

使用C#删除Excel表格中的重复行数据的代码详解

《使用C#删除Excel表格中的重复行数据的代码详解》重复行是指在Excel表格中完全相同的多行数据,删除这些重复行至关重要,因为它们不仅会干扰数据分析,还可能导致错误的决策和结论,所以本文给大家介绍... 目录简介使用工具C# 删除Excel工作表中的重复行语法工作原理实现代码C# 删除指定Excel单元

golang float和科学计数法转字符串的实现方式

《golangfloat和科学计数法转字符串的实现方式》:本文主要介绍golangfloat和科学计数法转字符串的实现方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望... 目录golang float和科学计数法转字符串需要对float转字符串做处理总结golang float

Python如何判断字符串中是否包含特殊字符并替换

《Python如何判断字符串中是否包含特殊字符并替换》这篇文章主要为大家详细介绍了如何使用Python实现判断字符串中是否包含特殊字符并使用空字符串替换掉,文中的示例代码讲解详细,感兴趣的小伙伴可以了... 目录python判断字符串中是否包含特殊字符方法一:使用正则表达式方法二:手动检查特定字符Pytho

windows和Linux安装Jmeter与简单使用方式

《windows和Linux安装Jmeter与简单使用方式》:本文主要介绍windows和Linux安装Jmeter与简单使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地... 目录Windows和linux安装Jmeter与简单使用一、下载安装包二、JDK安装1.windows设

MySQL 字符串截取函数及用法详解

《MySQL字符串截取函数及用法详解》在MySQL中,字符串截取是常见的操作,主要用于从字符串中提取特定部分,MySQL提供了多种函数来实现这一功能,包括LEFT()、RIGHT()、SUBST... 目录mysql 字符串截取函数详解RIGHT(str, length):从右侧截取指定长度的字符SUBST