LeetCode:459. 重复的子字符串 —【2、KMP算法】

news2024/12/22 23:46:53
🍎道阻且长,行则将至。🍓

🌻算法,不如说它是一种思考方式🍀


算法专栏: 👉🏻123


一、🌱459. 重复的子字符串

  • 题目描述:给定一个非空的字符串 s ,检查是否可以通过由它的一个子串重复多次构成。
  • 来源:力扣(LeetCode)
  • 难度:简单
  • 提示:
    1 <= s.length <= 104
    s 由小写英文字母组成
  • 示例 1:
    输入: s = “abab”
    输出: true
    解释: 可由子串 “ab” 重复两次构成。
    示例 2:
    输入: s = “aba”
    输出: false

🌴解题

枚举子字符串长度

使用两层 for 循环:
外层 for 遍历子字符串长度 i,所以遍历的范围是 1 ~ 字符串长度一半,注意字符串长度为 1 是不满足返回 false。对于每一个子字符串长度需要确定是否可以重复来构成原字符串,即用字符串长度对子字符串取余为 0。例如下图字符串这种情况就会出现错误判断:
在这里插入图片描述

内层 for 遍历字符串 j,直到结束(j+i < s.length()),如下图:
在这里插入图片描述
code:

class Solution {
    public boolean repeatedSubstringPattern(String s) {
        int n = s.length();
        if(n==1)
            return false;
        boolean tag=false;
        for(int i=1;i<=n/2;i++){//间隔
            if(n%i!=0)
                continue;
            for(int j=0;j+i<n;j++){
                if(s.charAt(j)!=s.charAt(j+i))
                    break;
                if((j+i==n-1)&&(s.charAt(j)==s.charAt(j+i)))
                    tag=true;
            }
            if(tag==true)
                break;
        }
        return tag;
    }    
}

在这里插入图片描述

一行代码~

我们先看个例子:
字符串是:s1 = abc abc,我们可以看出是重复子字符串构成的,如果我们把这个字符串复制追加到后面:s2 = abc abc abc abc,那么 s1 肯定是 s2 的一个子字符串,并且可以知道 s1 在 s2 中第 2 次出现的首个下标号是在字符串 s1 的范围内。

在这里插入图片描述
字符串是:s2 = abcabac,不是重复子字符串构成的:
在这里插入图片描述
是重复子字符串构成的字符串,就表示字符串是可以拆解的:s = s’ + s’,那么 S = s + s = s’ + s’ + s’ + s’ ,即第二次出现的位置不会超过字符串 s 的长度。
(s + s).indexOf(s, 1)就是表示字符串 s 在 index = 1 开始出现的下标。
所以可以写出如下代码:

class Solution {
    public boolean repeatedSubstringPattern(String s) {
        return (s + s).indexOf(s, 1) != s.length();
    }
}

在这里插入图片描述

KMP 方法

有了前面一种解题方法,那我们使用 KMP 算法也容易理解了,就是在 S 中找有没有子字符串 s,并且只能在 S 的前一半开始的子字符串。

class Solution {
    public boolean repeatedSubstringPattern(String s) {
        return kmp(s + s, s);
    }

    public boolean kmp(String query, String pattern) {
        int n = query.length();
        int m = pattern.length();
        int[] fail = new int[m];
        Arrays.fill(fail, -1);
        for (int i = 1; i < m; ++i) {
            int j = fail[i - 1];
            while (j != -1 && pattern.charAt(j + 1) != pattern.charAt(i)) {
                j = fail[j];
            }
            if (pattern.charAt(j + 1) == pattern.charAt(i)) {
                fail[i] = j + 1;
            }
        }
        int match = -1;
        for (int i = 1; i < n - 1; ++i) {
            while (match != -1 && pattern.charAt(match + 1) != query.charAt(i)) {
                match = fail[match];
            }
            if (pattern.charAt(match + 1) == query.charAt(i)) {
                ++match;
                if (match == m - 1) {
                    return true;
                }
            }
        }
        return false;
    }
}

在这里插入图片描述
对比上一个方法,在时间复杂度有了优化。(s + s).indexOf(s, 1) 就是一种字符串的暴力解法,源码:

    public static int indexOf(byte[] value, int valueCount, byte[] str, int strCount, int fromIndex) {
        byte first = str[0];
        int max = (valueCount - strCount);
        for (int i = fromIndex; i <= max; i++) {
            // 找到第一个匹配的字符
            if (value[i] != first) {
                while (++i <= max && value[i] != first);
            }
            // 找后面匹配的字符
            if (i <= max) {
                int j = i + 1;
                int end = j + strCount - 1;
                for (int k = 1; j < end && value[j] == str[k]; j++, k++);
                if (j == end) {
                    // 子字符串匹配,返回第一个字符的下标
                    return i;
                }
            }
        }
        return -1;
    }

    public static int indexOfLatin1Unsafe(byte[] src, int srcCount, byte[] tgt, int tgtCount, int fromIndex) {
        assert fromIndex >= 0;
        assert tgtCount > 0;
        assert tgtCount <= tgt.length;
        assert srcCount >= tgtCount;
        char first = (char)(tgt[0] & 0xff);
        int max = (srcCount - tgtCount);
        for (int i = fromIndex; i <= max; i++) {
            // 找到第一个匹配的字符
            if (getChar(src, i) != first) {
                while (++i <= max && getChar(src, i) != first);
            }
            // 找后面匹配的字符
            if (i <= max) {
                int j = i + 1;
                int end = j + tgtCount - 1;
                for (int k = 1;
                     j < end && getChar(src, j) == (tgt[k] & 0xff);
                     j++, k++);
                if (j == end) {
                    // 子字符串匹配
                    return i;
                }
            }
        }
        return -1;
    }

🌵 明月别枝惊鹊,清风半夜鸣蝉。

返回第一页。☝


☕物有本末,事有终始,知所先后。🍭

🍎☝☝☝☝☝我的CSDN☝☝☝☝☝☝🍓

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

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

相关文章

Docker数据管理与Docker镜像的创建

目录 1.管理数据的方式 1.数据卷 2.数据卷容器 3.容器互联&#xff08;使用centos镜像&#xff09; 2.Docker镜像的创建 1.基于现有镜像创建 2.基于本地模板创建 3.基于Dockerfile创建 4.Dockerfile案例 总结 1.管理数据的方式 容器中管理数据主要有两种方式&#xff1…

c++作业

自己定义mystring类实现string功能 #include <iostream> #include<cstring> using namespace std;class myString {private:char *str; //记录c风格的字符串int size; //记录字符串的实际长度public://无参构造myString():size(10){str new …

tomcat服务搭建

系列文章目录 文章目录 系列文章目录一、Tomcat1.核心功能 二、Tomcat服务搭建1.Tomcat服务2.Tomcat 虚拟主机配置1.创建 kgc 和 benet 项目目录和文件2.修改 Tomcat 主配置文件 server.xml3.客户端浏览器访问验证 三、Tomcat多实例部署 一、Tomcat 1.核心功能 1.connector&a…

Spring Bean生命周期源码之包扫描、创建BeanDefinition、合并BeanDefinition源码

文章目录 Bean生命周期源码生成BeanDefinitionSpring容器启动时创建单例Bean合并BeanDefinition Bean生命周期源码 我们创建一个ApplicationContext对象时&#xff0c;这其中主要会做两件时间&#xff1a;包扫描得到BeanDefinition的set集合&#xff0c;创建非懒加载的单例Bea…

体验ChatGPT在具体应用场景下的能力与表现——vuedraggable的move多次触发问题

当下人工智能模型在满天飞&#xff0c;今天拿一个具体的应用场景&#xff0c;来体验下ChatGPT的能力与表现&#xff0c;看看是否能解决实际问题。 顺便填一下之前遇到的一个具体的坑&#xff1a;vuedraggable的move多次触发问题。 背景 背景是这样的&#xff0c;实现低代码开…

Hadoop启动相关命令

Hadoop启动相关配置 文章目录 Hadoop启动相关配置格式化节点的情况什么情况下Hadoop需要进行格式化节点&#xff1f; Hadoop启动步骤Hadoop的启动步骤只是start-dfs.sh即可吗 *hdfs*的web管理页面参数说明参数的评价场景 格式化节点的情况 什么情况下Hadoop需要进行格式化节点…

赛效:怎么用改图鸭进行一键Logo设计?

改图鸭工具是一款在线图像处理工具&#xff0c;可以对图片进行大小调整、添加色彩、滤镜等&#xff0c;用户使用改图鸭可快速轻松地对多种图像进行处理操作&#xff0c;另外&#xff0c;改图鸭工具还支持一键进行Logo设计&#xff0c;很多人对改图鸭工具比较陌生&#xff0c;不…

rsync 服务器备份代码

rpm -qa | grep rsync #检查rsync软件是否存在 yum -y install rsync #安装rsync服务 systemctl start rsyncd #启动rsync服务 systemctl enable rsyncd #加入rsync开机启动 systemctl reload rsyncd #重新加载rsync netstat -lnp|grep 873 #检查是否已经成功启动 firewall…

【代码随想录】刷题Day2

1.左右指针比大小 977. 有序数组的平方 class Solution { public:vector<int> sortedSquares(vector<int>& nums) {vector<int> ret nums;int left 0;int right nums.size()-1;int end nums.size();while(left<right){if(abs(nums[left])>abs…

vue-element-admin-master编译异常记录

前言 最近一直在往大前端的方向转&#xff0c;不得不说前端的知识架构还真的很庞大&#xff0c;一步一个脚印吧&#xff0c;之前消化完极简版后台项目[vue-admin-template-master]后&#xff0c;开始想看下完整版的后台[vue-element-admin-master]项目&#xff0c;奈何clone项…

ChatGPT实战100例 - (08) 设计转化为SQL并获取ER图

文章目录 ChatGPT实战100例 - (08) 设计转化为SQL并获取ER图一、需求与思路二、SQL建表三、绘制四、 总结 ChatGPT实战100例 - (08) 设计转化为SQL并获取ER图 一、需求与思路 在你还在手撸SQL&#xff1f;ChatGPT笑晕在厕所 这篇博文中 针对经典3表设计&#xff1a; 学生表 S…

【我在CSDN成长】我的两周年创作纪念日

【我在CSDN成长】我的两周年创作纪念日 一、来到CSDN的大家庭二、在CSDN的收获1.在CSDN的感受2.在CSDN的收获 三、在CSDN的未来规划憧憬 一、来到CSDN的大家庭 当看到这个信息时&#xff0c;才发现不知不觉已经在CSDN创作两年了&#xff0c;今天才腾出时间来写下这篇博文。感叹…

绕开坑坑,申请高德地图安卓appKey的步骤

在申请高德地图 appkey的时候&#xff0c;我们会采用keytool的方法来生成sha1码。这里面有坑&#xff0c;请看 PS C:\Users\cuclife.android> keytool -v -list -keystore keystore keytool 错误: java.lang.Exception: 密钥库文件不存在: keystore java.lang.Exception: 密…

涨点技巧:IOU篇---Yolov5/Yolov7引入WIoU,SIoU,EIoU,α-IoU

1.IOU介绍 IoU其实是Intersection over Union的简称,也叫‘交并比’。IoU在目标检测以及语义分割中,都有着至关重要的作用。 首先,我们先来了解一下IoU的定义: 我们可以把IoU的值定为为两个图形面积的交集和并集的比值,如下图所示: 1.1 Yolov5自带IOU方法 GIoU, DIoU,…

Kubernetes(k8s 1.23.17) 基于docker 一主两从集群环境搭建

结合网上资料&#xff0c;利用k8s最后直接支持docker的版本1.23.17搭建&#xff0c;并本地验证完成。 1 虚拟机准备 1.1 规划 系统角色/hostnameIP地址配置CentOS 7.9 &#xff08;需要7.5&#xff09;master192.168.68.1002Core、4G内存、40GB磁盘CentOS 7.9 &#xff08;需…

一篇文章告诉你,为什么移动数据捕获对运输物流公司很重要?

随着世界走向数字化和智能手机的使用增加&#xff0c;移动数据采集正在成为大多数行业的新常态。航运物流也不例外。从捕获详细的订单和交付信息到跟踪货运和仓库位置&#xff0c;条形码技术用于运输物流世界的每一步。通过智能数据采集&#xff0c;运输和物流公司可以获得更好…

camunda的service task如何使用

在 Camunda 中&#xff0c;使用 Service Task 节点可以执行各种类型的业务逻辑&#xff0c;例如计算、数据转换、数据格式化等。在 Service Task 节点中&#xff0c;可以使用不同的编程语言来实现业务逻辑&#xff0c;例如 Java、JavaScript、Python 等。 下面是使用 Java 实现…

生产制造企业如何建立适合自身的数字化工厂,实现数字化转型?

“工业4.0”这一全新的术语受到全球的瞩目&#xff0c;它是继机械化、电气化和信息技术之后&#xff0c;以智能制造为核心的第四次工业革命。“工业4.0”最显著的特征是智能工厂的广泛普及。而智能工厂是在数字化工厂的基础上发展而来的&#xff0c;没有数字化就没有智能化。因…

如何在低代码平台上构建ERP软件

ERP软件是企业管理日常运营需求的关键组件。然而&#xff0c;对于许多企业&#xff0c;尤其是资源有限的企业来说&#xff0c;尝试构建和管理ERP平台可能要担负较高的成本的。幸运的是&#xff0c;低代码平台可以使这个过程变得容易得多。今天我们来解释如何在低代码平台上构建…

【IDEA】数据湖 Hudi 0.12.0 基础使用

文章目录 创建 Maven 项目插入数据查询数据更新数据增量查询删除数据 前言 集群系统&#xff1a;CentOS 7.5 服务器信息&#xff1a; 服务器角色IPhadoop104服务器Master192.168.0.104hadoop105服务器Slave1192.168.0.105hadoop106服务器Slave2192.168.0.106 使用的组件版本…