重复的子字符串

力扣题目链接(opens new window)

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

示例 1:

输入: "abab"

输出: True

解释: 可由子字符串 "ab" 重复两次构成。

示例 2:

输入: "aba"

输出: False

示例 3:

输入: "abcabcabcabc"

输出: True

解释: 可由子字符串 "abc" 重复四次构成。 (或者子字符串 "abcabc" 重复两次构成。)

思路

考虑使用KMP,但是无法确定模式串(即,如何找出可重复的子串)

如果使用for循环去找,那么找到之后还需要再套一层for循环去匹配

复杂度爆了,因此不太可行

移动匹配

不使用KMP算法也可以

思路大概是这样的

实际处理时,我们将两个字符串拼接之后,如何搜索是否再次出现原字符串呢?

只需要把拼接字符串掐头去尾,然后使用find查找即可

代码
class Solution {
public:
bool repeatedSubstringPattern(string s) {
//拼接字符串
string mix = s + s;
//掐头去尾
mix.erase(mix.begin());
mix.erase(mix.end() - 1);
//在拼接串中找s
if(mix.find(s) != string::npos){
return true;
}
return false;
}
};

注意:string::npos是作为有无匹配项的判别条件,详见

KMP

思路
大体思路

使用KMP算法也可以

回顾一下,KMP算法是用来干嘛的?找出一个字符串中是否存在目标子串

在这个过程中,我们需要去求模式串的前缀表并且构建next数组,当遇到字符不匹配的时候可以找到上一个匹配过的位置继续匹配。

前缀表中保存了以字符串各个位置为终点的最长相同前后缀的长度

利用最长相同前后缀便可以求出重复子串

前后缀的定义

先再次明确一下前后缀的定义:以"ABCDABD"为例(参考

	- "A"的前缀和后缀都为空集,共有元素的长度为0;

  - "AB"的前缀为[A],后缀为[B],共有元素的长度为0;

  - "ABC"的前缀为[A, AB],后缀为[BC, C],共有元素的长度0;

  - "ABCD"的前缀为[A, AB, ABC],后缀为[BCD, CD, D],共有元素的长度为0;

  - "ABCDA"的前缀为[A, AB, ABC, ABCD],后缀为[BCDA, CDA, DA, A],共有元素为"A",长度为1;

  - "ABCDAB"的前缀为[A, AB, ABC, ABCD, ABCDA],后缀为[BCDAB, CDAB, DAB, AB, B],共有元素为"AB",长度为2;

  - "ABCDABD"的前缀为[A, AB, ABC, ABCD, ABCDA, ABCDAB],后缀为[BCDABD, CDABD, DABD, ABD, BD, D],共有元素的长度为0。

这里有个关键点:

前后缀是对于整个字符串来说的,而不是针对字符串中某个字符

一种经典错误思想是:"AB"中,B的前缀是A,A的后缀是B;

最小重复子串

搞清楚上面的概念之后,以字符串"augaugaugaug"为例

你会发现, 由重复子串组成的字符串("augaugaugaug")中,最长相等前后缀不包含的子串("aug")就是最小重复子串

而KMP正好可以求这玩意(最长相等前后缀),巧了!

具体思路

字符串"augaugaugaug"的长度,len = 12;

现在要引入next数组(计算方式详见),如图所示(前缀表统一减一,即 j 的初始值为 -1)

如果 next[len - 1]不为-1,则说明字符串有最长相同的前后缀

获取最长相等前后缀的长度

该长度实际上就是next数组中下标为 len-1 位置的值,即next[len-1]

因为是从0开始算的,所以要加个1补回来(本质上是由前缀表统一减一的缘故导致的),即next[len-1]+1

用字符串数组的长度len减去该长度

得到一个子串M的长度len - (next[len-1]+1)

然后用该子串长度再与len做取模运算

如果能够整除(即len % (len - (next[len - 1] + 1)) == 0),说明整个字符串都是由子串M组成的

代码
class Solution {
public:
//创建获取计算next数组的函数
void getNext(int* next, string& s){
//初始化j和next
int j = -1;
next[0] = j;
//开始遍历输入串
for(int i = 1; i < s.size(); ++i){//注意i从1开始
//不匹配,回退
while(j >= 0 && s[j + 1] != s[i]){
j = next[j];
}
//匹配,将j值记录到next数组,两个指针后移
if(s[j + 1] == s[i]){
j++;
}
next[i] = j;
}
} bool repeatedSubstringPattern(string s) {
//创建next数组
int next[s.size()];
//计算next数组
getNext(next, s);
//求输入串的长度
int len = s.size();
if (next[len - 1] != -1 && len % (len - (next[len - 1] + 1)) == 0) {//条件不要漏了,如果本来字符串就没有最大相等前后缀也就不用判断了
return true;
}
return false;
}
};
易错点

1、getNext函数中指针 i 从1开始,另外一个指针应该是 j+1 而不是 j

2、如果输入串都不存在最大相等前后缀,那么可以直接返回false,

​ 即别忘了条件next[len - 1] != -1

【LeetCode字符串#06】KMP巩固练习:重复子串的更多相关文章

  1. 基于python 3.5 所做的找出来一个字符串中最长不重复子串算法

    功能:找出来一个字符串中最长不重复子串 def find_longest_no_repeat_substr(one_str): #定义一个列表用于存储非重复字符子串 res_list=[] #获得字符 ...

  2. [leetcode](4.21)3. 最长重复子串

    给定字符串 S,找出最长重复子串的长度.如果不存在重复子串就返回 0. 示例 1: 输入:"abcd" 输出:0 解释:没有重复子串. 示例 2: 输入:"abbaba& ...

  3. 【TOJ 2406】Power Strings(KMP找最多重复子串)

    描述 Given two strings a and b we define a*b to be their concatenation. For example, if a = "abc& ...

  4. leetcode.字符串.5最长回文子串-Java

    1. 具体题目 给定一个字符串 s,找到 s 中最长的回文子串.你可以假设 s 的最大长度为 1000. 示例 1: 输入: "babad" 输出: "bab" ...

  5. HDU-2087 剪花布条 字符串问题 KMP算法 查匹配子串

    题目链接:https://cn.vjudge.net/problem/HDU-2087 题意 中文题咯 一块花布条,里面有些图案,另有一块直接可用的小饰条,里面也有一些图案.对于给定的花布条和小饰条, ...

  6. poj 1743 Musical Theme(最长重复子串 后缀数组)

    poj 1743 Musical Theme(最长重复子串 后缀数组) 有N(1 <= N <=20000)个音符的序列来表示一首乐曲,每个音符都是1..88范围内的整数,现在要找一个重复 ...

  7. [LeetCode] Longest Substring Without Repeating Characters 最长无重复子串

    Given a string, find the length of the longest substring without repeating characters. For example, ...

  8. 图解leetcode —— 395. 至少有K个重复字符的最长子串

    前言: 每道题附带动态示意图,提供java.python两种语言答案,力求提供leetcode最优解. 描述: 找到给定字符串(由小写字符组成)中的最长子串 T , 要求 T 中的每一字符出现次数都不 ...

  9. [LeetCode] 3.Longest Substring Without Repeating Characters 最长无重复子串

    Given a string, find the length of the longest substring without repeating characters. Example 1: In ...

  10. LeetCode:Longest Substring Without Repeating Characters(最长不重复子串)

    题目链接 Given a string, find the length of the longest substring without repeating characters. For exam ...

随机推荐

  1. Java项目有可能做到所有的代码逻辑均可热部署吗?

    前言 首先我们明确下什么叫做热部署,热部署是在不重启java虚拟机的前提下,自动更新class的行为,从而更新整个运行时的逻辑. 在java开发领域,热部署一直是一个难以解决的问题,java虚拟机理论 ...

  2. Git 实战分支版本管理策略 | TBD++ Flow

    ​简介 随着Git的普及,为了更高效地进行团队协作开发,人们通过经验总结研究出了几套适用于各种团队和项目的分支管理策略,上篇文章我们讲解了 Git Flow 代码版本管理策略,它对版本控制较为严格,主 ...

  3. Revit2021保姆级安装教程

    Revit2021 WIN10 64位安装步骤: 1.先使用"百度网盘客户端"下载Revit_2021软件安装包到电脑磁盘里,并解压缩,安装全程需连接网络,然后双击打开Revit_ ...

  4. 线程(Thread)基本用法

    一.线程的调用 1.无参 def run_01(): for i in range(6, 10): print("test01", i) time.sleep(1) th_01 = ...

  5. 篇(16)-Asp.Net Core入门实战-权限管理之用户创建与关联角色(ViewModel再用与模型验证二)

    入门实战-权限管理之用户创建与关联角色(ViewModel再用与模型验证二) (1).在用户管理着模块中,相比较菜单功能的代码还是比较多的,设计到用户的创建,修改,角色变更和密码重置,同时都集中在列表 ...

  6. .net如何优雅的使用EFCore

    EFCore是微软官方的一款ORM框架,主要是用于实体和数据库对象之间的操作.功能非常强大,在老版本的时候叫做EF,后来.net core问世,EFCore也随之问世. 本文我们将用一个控制台项目Ho ...

  7. ArcObjects SDK开发 007 自定义App-Command-Tool框架

    1.为什么再设计一套App-Command-Tool框架 为什么我们要自己再设计一套App-Command框架,而不直接使用AO API中的AxControl-ICommand这套已经非常好的框架呢? ...

  8. 数电第11周周结_by_yc

    Lab7_时序逻辑验证 一.简易电子时钟 功能描述:   设计一简易电子时钟,支持时.分.秒显示,其中HEX7-HEX6显示时,HEX5-HEX4显示分,HEX1-HEX0显示秒,假设进制为:18秒= ...

  9. 更改HTML请求方式的几种方法

    以ctfhub中的请求方式题目为例,则可以有: 法一:通过burpsuite抓包修改 在burpsuite中抓包后发送到repeater模块中,对请求方式进行修改即可 法二:通过curl命令进行 cu ...

  10. 【Shell案例】【小数点scale&bc】14、求平均值

    描述写一个bash脚本以实现一个需求,求输入的一个的数组的平均值 第1行为输入的数组长度N第2~N行为数组的元素,如以下为:数组长度为4,数组元素为1 2 9 8示例:41298 那么平均值为:5.0 ...