【算法与数据结构】459、LeetCode重复的子字符串

文章目录

  • 一、题目
  • 二、解法
    • 2.1 暴力破解法
    • 2.2 KMP算法
    • 2.3 Sunday算法
    • 2.4 官方查找算法
  • 三、完整代码

所有的LeetCode题解索引,可以看这篇文章——【算法和数据结构】LeetCode题解。

一、题目

在这里插入图片描述

二、解法

2.1 暴力破解法

  思路分析:子串多次循环才能构成整个字符串,那么很容易想到使用一个for循环确定子串终止的位置,然后另一个for循环去遍历整个字符串。这道题在用暴力破解时也可以做简化,至少有两个子串,因此循环到 len/2 即可。
  程序如下

    // 暴力破解法bool repeatedSubstringPattern3(string s) {        int len = s.size();for (int i = 0; i < len / 2; i++) {     // 匹配到n/2if (len % (i + 1)) continue;        // 判断len是不是i+1的倍数,是倍数就进入循环bool flag = true;for (int j = i + 1; j < len; ++j) { if (s[j] != s[j % (i + 1)]) {flag = false;break;}}if (flag) return true;}return false;}

复杂度分析:

  • 时间复杂度: O ( n 2 ) O(n^2) O(n2)
  • 空间复杂度: O ( 1 ) O(1) O(1)

2.2 KMP算法

  思路分析如果是重复子串构成的字符串,前面有相同的子串,后面有相同的子串,用 s + s,这样组成的字符串中,后面的子串做前串,前后的子串做后串,就一定还能组成一个s。那么我们在 s+s 当中掐头去尾,在中间找到一个s那么说明这个字符串是一个循环子串构成的字符串。
  程序如下

    // KMP算法实现void getNext(int* next, string s) {int j = -1; next[0] = j;for (int i = 1; i < s.size(); i++) {while (j >= 0 && s[i] != s[j + 1]) {j = next[j];}if (s[i] == s[j + 1]) {j++;}next[i] = j;}}bool repeatedSubstringPattern4(string s) {if (!s.size()) return false;int* next = new int[s.size()];getNext(next, s);int len = s.size();if (next[len - 1] != -1 && len % (len - (next[len - 1] + 1)) == 0)  return true;return false;}

复杂度分析:

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

2.3 Sunday算法

  思路分析:思路和KMP算法相同,就是查找算法变成了Sunday算法,关于Sunday算法大家可以参考笔者这片文章【算法与数据结构】字符串匹配算法。
  程序如下

    // Sunday算法   int Sunday(string haystack, string needle) {if (haystack.size() < needle.size()) return -1;     // 检查合法性if (!needle.size()) return 0;                       // needle为空返回0  int shift_table[128] = { 0 };       // 128为ASCII码表长度for (int i = 0; i < 128; i++) {     // 偏移表默认值设置为 模式串长度 + 1shift_table[i] = needle.size() + 1;}for (int i = 0; i < needle.size(); i++) {	// 如果有重复字符也会覆盖,确保shift_table是 模式串最右端的字符到末尾的距离 + 1shift_table[needle[i]] = needle.size() - i;}int s = 0; // 文本串初始位置int j;while (s <= haystack.size() - needle.size()) {j = 0;while (haystack[s + j] == needle[j]) {++j;if (j >= needle.size()) return s;   // 匹配成功}// 找到主串中当前跟模式串匹配的最末字符的下一个字符// 在模式串中出现最后的位置// 所需要从(模式串末尾+1)移动到该位置的步数s += shift_table[haystack[s + needle.size()]];}return -1;}bool repeatedSubstringPattern(string s) {return Sunday((s + s).substr(1, 2 * s.size() - 2), s) != -1 ? true : false;}

复杂度分析:

  • 时间复杂度: 平均时间复杂度为 O ( n ) O(n) O(n),最坏情况时间复杂度为 O ( n ∗ m ) O(n*m) O(nm)
  • 空间复杂度: O ( 1 ) O(1) O(1),常量存储空间。

2.4 官方查找算法

  

    // 使用官方查找算法bool repeatedSubstringPattern2(string s) {return (s + s).find(s, 1) != s.size();}

复杂度分析:

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

三、完整代码

# include <iostream>
# include <string>
using namespace std;class Solution {
public:// Sunday算法   int Sunday(string haystack, string needle) {if (haystack.size() < needle.size()) return -1;     // 检查合法性if (!needle.size()) return 0;                       // needle为空返回0  int shift_table[128] = { 0 };       // 128为ASCII码表长度for (int i = 0; i < 128; i++) {     // 偏移表默认值设置为 模式串长度 + 1shift_table[i] = needle.size() + 1;}for (int i = 0; i < needle.size(); i++) {	// 如果有重复字符也会覆盖,确保shift_table是 模式串最右端的字符到末尾的距离 + 1shift_table[needle[i]] = needle.size() - i;}int s = 0; // 文本串初始位置int j;while (s <= haystack.size() - needle.size()) {j = 0;while (haystack[s + j] == needle[j]) {++j;if (j >= needle.size()) return s;   // 匹配成功}// 找到主串中当前跟模式串匹配的最末字符的下一个字符// 在模式串中出现最后的位置// 所需要从(模式串末尾+1)移动到该位置的步数s += shift_table[haystack[s + needle.size()]];}return -1;}bool repeatedSubstringPattern(string s) {return Sunday((s + s).substr(1, 2 * s.size() - 2), s) != -1 ? true : false;}// 使用官方查找算法bool repeatedSubstringPattern2(string s) {return (s + s).find(s, 1) != s.size();}// 暴力破解法bool repeatedSubstringPattern3(string s) {        int len = s.size();for (int i = 0; i < len / 2; i++) {     // 匹配到n/2if (len % (i + 1)) continue;        // 判断len是不是i+1的倍数,是倍数就进入循环bool flag = true;for (int j = i + 1; j < len; j++) { if (s[j] != s[j % (i + 1)]) {flag = false;break;}}if (flag) return true;}return false;}// KMP算法实现void getNext(int* next, string s) {int j = -1; next[0] = j;for (int i = 1; i < s.size(); i++) {while (j >= 0 && s[i] != s[j + 1]) {j = next[j];}if (s[i] == s[j + 1]) {j++;}next[i] = j;}}bool repeatedSubstringPattern4(string s) {if (!s.size()) return false;int* next = new int[s.size()];getNext(next, s);int len = s.size();if (next[len - 1] != -1 && len % (len - (next[len - 1] + 1)) == 0)  return true;return false;}
};int main()
{//string s = "abab";//string s = "aba";string s = "abcabcabcabc";Solution s1;bool result = s1.repeatedSubstringPattern3(s);cout << "目标字符串" << s <<"是否由重复子串构成:" << endl;if (!result) cout << "否" << endl;else cout << "是" << endl;system("pause");return 0;
}

end

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

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

相关文章

使用docker安装redis并使用redis deskTop manager连接

使用docker安装redis 提前准备环境 linux、 docker环境 # 使用命令查看docker环境是否正常docker images(任何一个docker命令就可以&#xff0c;不一定必须这个) 下载redis镜像 # 使用命令下载镜像文件docker pull redis 确认镜像 # 使用命令查看镜像docker images使用redis d…

[桌面运维]PC常用的视频接口,显示器VGA、DVI、HDMI、DP、USB-C接口的认识和应用

⬜⬜⬜ &#x1f430;&#x1f7e7;&#x1f7e8;&#x1f7e9;&#x1f7e6;&#x1f7ea;(*^▽^*)欢迎光临 &#x1f7e7;&#x1f7e8;&#x1f7e9;&#x1f7e6;&#x1f7ea;&#x1f430;⬜⬜⬜ ✏️write in front✏️ &#x1f4dd;个人主页&#xff1a;陈丹宇jmu &am…

MySQL-分库分表详解(五)

♥️作者&#xff1a;小刘在C站 ♥️个人主页&#xff1a; 小刘主页 ♥️努力不一定有回报&#xff0c;但一定会有收获加油&#xff01;一起努力&#xff0c;共赴美好人生&#xff01; ♥️学习两年总结出的运维经验&#xff0c;以及思科模拟器全套网络实验教程。专栏&#xf…

【海量数据挖掘/数据分析】之 决策树模型(决策树模型、决策树构成、决策树常用算法、决策树性能要求、信息增益、信息增益计算公式、决策树信息增益计算实例)

【海量数据挖掘/数据分析】之 决策树模型&#xff08;决策树模型、决策树构成、决策树常用算法、决策树性能要求、信息增益、信息增益计算公式、决策树信息增益计算实例&#xff09; 目录 【海量数据挖掘/数据分析】之 决策树模型&#xff08;决策树模型、决策树构成、决策树常…

pytorch—实现各种注意力

1.什么是Attention 所谓Attention机制&#xff0c;便是聚焦于局部信息的机制&#xff0c;比如图像中的某一个图像区域。随着任务的变化&#xff0c;注意力区域往往会发生变化。 面对上面这样的一张图&#xff0c;如果你只是从整体来看&#xff0c;只看到了很多人头&#xff0c…

SpringBoot——2.7.3版本整合Swagger3

前言 Swagger2&#xff08;基于openApi3&#xff09;已经在17年停止维护了&#xff0c;取而代之的是 sagger3&#xff08;基于openApi3&#xff09;&#xff0c;而国内几乎没有 sagger3使用的文档&#xff0c;百度搜出来的大部分都是swagger2的使用&#xff0c;这篇文章将介绍…

RabbitMQ系列(22)--RabbitMQ优先级队列

前言&#xff1a;在购物系统中有一个订单催付的场景&#xff0c;如果客户在购物系统下单后在设定的时间内未付款那么就会给客户推送一条短信提醒&#xff0c;这是一个比较简单的功能&#xff0c;但是&#xff0c;商家对我们来说&#xff0c;肯定是要区分大客户和小客户的&#…

设计合并排序算法实现对N个整数排序。

1.题目 设计合并排序算法实现对N个整数排序 2.设计思路 先将无序序列利用分治法划分为子序列&#xff0c;直至每个子序列只有一个元素&#xff0c;然后再对有序子序列逐步进行合并排序。合并方法是循环的将两个有序子序列当前的首元素进行比较&#xff0c;较小的元素取出&…

Node中的模块引擎EJS模块渲染

1.导入 const ejsrequire("ejs") 2.声明数组 const group["张三","李四","王二","麻子"] 3.EJS实现 let resultejs.render(<ul> <% group.forEach(item>{ %> <li><%item%></li> <% }) …

Kotlin单例模式的一种懒汉模式写法

Kotlin单例模式的一种懒汉模式写法 class MyHelpler {companion object {private val singleHelpler by lazy(mode LazyThreadSafetyMode.SYNCHRONIZED) { MyHelpler() }fun instance() singleHelpler}fun sayHi() {println("fly")} }fun main(args: Array<Stri…

BOM操作

JavaScript组成 BOM 浏览器对象模型 window对象 是一个全局对象&#xff0c;也就是JavaScript中的顶级对象 像document&#xff0c;alert() console.log() 都是window对象的属性&#xff0c; 基本的BOM的属性和方法都属于window对象 通过var定义在全局作用域中的变量&#x…

从开机开始

1. 开机之后&#xff0c;计算机干了什么&#xff1f; 加载BIOS&#xff1a;计算机通电后&#xff0c;基本输入/输出系统&#xff08;BIOS&#xff09;会首先运行。BIOS是一个固件程序&#xff0c;它位于计算机主板上的芯片中&#xff0c;并负责初始化硬件设备、检测和解决问题…