(第15天)【leetcode题解】459、重复的子字符串

ops/2024/10/18 14:18:51/

目录

  • 459、重复的子字符串
    • 题目描述
    • 暴力匹配
      • 思路
      • 代码
    • 字符串匹配
      • 思路
      • 代码
      • 与暴力匹配的不同
    • KMP解法
      • 思路
      • 代码
      • KMP算法的核心和用途

459、重复的子字符串

题目描述

给定一个非空的字符串 s ,检查是否可以通过由它的一个子串重复多次构成。

暴力匹配

思路

  1. 推理
  • 如果存在这样的子串,那么这个子串一定是s的前缀
  • s的长度n一定是子串长度n1的整数倍
  • s中的元素s[i]与往前移n1的元素s[i-n1]相同
  1. 方法

因此从小到大枚举出所有可能的子串长度n1,再对这个子串进行上述的判断即可。
优化:这个子串至少要在s中重复一次,所以n1的范围为[1,n/2]。

代码

class Solution {
public:bool repeatedSubstringPattern(string s) {int n = s.size();//i代表子串的长度,应从1开始for (int i = 1; i <= n / 2; i++) {//判断该子串是否为目标子串if (n % i == 0) {bool match = true;//判断之后的字符往前移子串长度i之后是否相等//从子串之后开始遍历整个字符串for (int j = i; j < n; j++) {if (s[j] != s[j - i]) {match = false;break;} }if (match) return true;}}return false;}
};

时间复杂度:O(n2);枚举子串的时间复杂度为O(n),遍历判断子串的时间复杂度为O(n)。
空间复杂度:O(1);

字符串匹配

思路

  1. 如果s满足题目要求,那么s具有以下性质:
  • 设s的长度为n,子串长度s1为n1.
  • 可以把s写成n/n1个子串s1排列的形式 : s——>s1s1s1s1…
  • 那么把第一个s1移到最后面,字符串s不变
  1. 根据性质,可以证明:
  • 因为1 <= n1 < n,那么把两个字符串s连在一起得到S
  • 把连在一起后的字符串S移除前后第一个元素
  • 这时,字符串s一定是拼接串S的子串
  1. 根据证明结果,得到方法:
  • 拼接两个字符串s
  • 移除第一个和最后一个字符
  • 如果s是其中的子串,则满足题目要求

代码

class Solution {
public:bool repeatedSubstringPattern(string s) {return (s + s).find(s, 1) != s.size();}
};

与暴力匹配的不同

通过推理,得到一种满足要求是的情况,只要针对这个情况进行判断即可。

KMP解法

思路

  1. 假设推理
  • 假设这个文本串由重复子串组成
  • 找到这个文本串的最长公共前后缀
  • 文本串切割掉最长公共前后缀,剩下的就是重复子串
  1. 可用的结论
  • 设文本串s由n个长度为x的子串组成,则文本串全长为nx
  • 最长公共前后缀由m个长度为x的子串组成,长度为mx
  • 则重复子串长度为(n-m)xn-m=1
  • 当全长nx对重复子串长度(n-m)x取余等于0时(即nx % (n-m)x == 0 or nx % x == 0),证明(n-m)x代表的子串为重复子字符串。
  1. 方法
  • 求出next数组,next数组长度为len
  • 使用next数组存储文本串中最长公共前后缀的长度next[len - 1]
  • 如果 len % (len -next[len - 1]) == 0,则表明存在重复子字符串

代码

class Solution {
public://得出next数组void getNext(int* next, string& s) {//初始化int j = 0;//前缀末尾从0开始next[0] = j;//从长度为2的子串开始求最长公共前后缀长度for (int i = 1; i < s.size(); i++) {//前后缀末尾不匹配时while (j >0 && s[i] != s[j]) j = next[j - 1];//j回退//前后缀末尾匹配时if (s[i] == s[j]) {j++;//j(和i)往后移一位}next[i] = j;//下标j为当前子串(末尾下标为i)的最长公共前后缀长度}}bool repeatedSubstringPattern(string s) {int next[s.size()];//创建长度为字符串长度的前缀表getNext(&next[0], s);//使用最长公共前后缀长度判断是否由重复的子字符串组成int len = s.size();//next[len - 1] == 0时,证明整个字符串最长公共前后缀长度为0//根据推理得出的结论:当len % (len - next[len-1]) == 0 时证明(有重复的子字符串/最后一段字符串为重复子字符串)if (next[len - 1] != 0 && len % (len - next[len-1]) == 0) return true;return false;}
};

时间复杂度:O(n);得到前缀表时遍历字符串需要O(n),判断重复子字符串只用了固定的操作数。
空间复杂度:O(n);需要前缀表存储字符串的所有前缀子串(包括它自身)的最长公共前后缀长度。

KMP算法的核心和用途

  1. 核心
  • 前缀表next,其中存储了字符串的最长公共前后缀长度
  • 匹配时,使用前缀表记录的最长公共前后缀长度来进行回退
  • 总结:存储字符串的最长公共前后缀长度的前缀表、回退思想。
  1. 用途
  • 使用前缀表回退查找子字符串。
  • 使用前缀表中记录的最长公共前后缀长度来进行一些数字上的判断。

http://www.ppmy.cn/ops/39206.html

相关文章

内存拆解分析表:学习版[图片]

对拆解system中主要是对比测试机和对比机之间的差距&#xff0c;测试机那些地方高于对比机 拆解表&#xff0c;作为理解 在拆解表中system测试机比对比机多出113M 这说明是有问题的 对system拆解&#xff1a; system12345对比机9102294380941069391081628测试机10252010331…

服务端JavaScript(Node.js)与去IO编程:Node.js的事件驱动和非阻塞IO模型,它是如何使JavaScript走向后端的

在Node.js中&#xff0c;JavaScript代码运行在V8引擎上。由于JavaScript是单线程语言&#xff0c;一次只能处理一个事件。为了解决这个问题&#xff0c;Node.js引入了事件驱动模型。每个进行IO操作的函数都是异步的&#xff0c;当这个函数被调用的时候&#xff0c;它不会立即执…

一键追爆款,GPT一键改文‌‍‬⁣⁡​⁤⁢​⁢⁡⁣‬‍‌​​‬ ​‍⁤‬ ‬⁡⁡⁡‍‌‬⁡⁡⁢‬⁤⁢⁢⁤​‍‌​​‬ ​⁣‌,绘唐3,绘唐工具

ai画影满足你的制作要求 一键追爆款&#xff0c;GPT一键改文 AI推文小说&漫画解说&解压混剪 人物定义&#xff0c;角色定义&#xff0c;lora转换&#xff0c;模型转换&#xff0c;可视化参考满足 一键追爆款 一键挂机生成&#xff0c;效果更精彩&#xff0c;使用更方…

设计模式——享元模式(Flyweight)

享元模式&#xff08;Flyweight Pattern&#xff09;是一种软件设计模式&#xff0c;它运用共享技术来有效地支持大量细粒度对象的复用。以下是关于享元模式的详细解释&#xff1a; 定义 享元模式使用共享物件&#xff0c;以尽可能减少内存使用量以及分享信息给尽可能多的相似…

android进阶-Binder

参考&#xff1a;Android——Binder机制-CSDN博客 机制&#xff1a;Binder是一种进程间通信的机制 驱动&#xff1a;Binder是一个虚拟物理设备驱动 应用层&#xff1a;Binder是一个能发起进程间通信的JAVA类 Binder相对于传统的Socket方式&#xff0c;更加高效Binder数据拷贝…

【网络安全】一次sql注入问题的处理

目录 问题 10.60.100.194&#xff0c;修改之前 修改方案 问题解决 测试过程 问题思考与总结 问题 一次sql注入问题的筛查报告&#xff0c;主要是sql注入的问题资源-CSDN文库 doc-new\20-设计文档\34-Mesh设备管理\100-网络安全 10.60.100.194&#xff0c;修改之前 修改…

使用单片机的IO引脚直接驱动段码屏

使用单片机的IO引脚直接驱动段码屏,目的是为了降低成本。这种古老的应用,在低功耗产品中比较多见。 如:水表&#xff0c;燃气表等需要电池供电的产品。 下面纯属个人理解&#xff0c;未经测试。 1/3Duty表示LCD共有3个COM引脚,分别占显示周期的1/3 1/2BIAS表示电压0和VCC 1、…

使用com.google.common.collect依赖包中的Lists.transform()方法转换集合对象之后,修改集合中的对象属性,发现不生效

目录 1.1、错误描述 &#xff08;1&#xff09;引入依赖 &#xff08;2&#xff09;模拟代码 &#xff08;3&#xff09;运行结果 1.2、解决方案 1.1、错误描述 最近在开发过程中&#xff0c;使用到了com.google.common.collect依赖包&#xff0c;通过这个依赖包中提供的…