字符串——459. 重复的子字符串

简介: 本专栏按照数组—链表—哈希—字符串—栈与队列—二叉树—回溯—贪心—动态规划—单调栈的顺序刷题,采用代码随想录所给的刷题顺序,一个正确的刷题顺序对算法学习是非常重要的,希望对大家有帮助

1 题目描述

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

2 题目示例

示例 1:
输入: s = "abab"
输出: true
解释: 可由子串 "ab" 重复两次构成。

示例 2:
输入: s = "aba"
输出: false

示例 3:
输入: s = "abcabcabcabc"
输出: true
解释: 可由子串 "abc" 重复四次构成。 (或子串 "abcabc" 重复两次构成。)

3 题目提示

1 <= s.length <= 104
s 由小写英文字母组成

4 思路

方法一:字符串匹配
我们可以把字符串 ss 写成s's'···s's'的形式。

如果我们移除字符串s的前n'个字符(即一个完整的s'),再将这些字符保持顺序添加到剩余字符串的末尾,那么得到的字符串仍然是s。由于1 ≤ n'≤ n,那么如果将两个s连在一起,并移除第一个和最后一个字符,那么得到的字符串—定包含s,即s是它的一个子串。
因此我们可以考虑这种方法:我们将两个s连在一起,并移除第一个和最后一个字符。如果s是该字符串的子串,那么s就满足题目要求。
证明需要使用一些同余运算的小技巧,可以见方法三之后的「正确性证明」部分。这里先假设我们已经完成了证明,这样就可以使用非常简短的代码完成本题。在下面的代码中,我们可以从位置 11 开始查询,并希望查询结果不为位置 nn,这与移除字符串的第一个和最后一个字符是等价的。

复杂度分析

由于我们使用了语言自带的字符串查找函数,因此这里不深入分析其时空复杂度。

方法二::KMP 算法
由于本题就是在一个字符串中查询另一个字符串是否出现,可以直接套用 KMP 算法。因此这里对 KMP 算法本身不再赘述。读者可以自行查阅资料进行学习。

5 我的答案

class Solution {
    public boolean repeatedSubstringPattern(String s) {
        return (s + s).indexOf(s, 1) != s.length();
    }
}
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;
    }
}
相关文章
|
Arthas 测试技术
【面试题精讲】JVM-类加载器-使用Arthas查看类加载器
【面试题精讲】JVM-类加载器-使用Arthas查看类加载器
【面试题精讲】JVM-类加载器-使用Arthas查看类加载器
|
前端开发 安全 Java
类加载器原理
一、类加载 二、链接 三、初始化
类加载器原理
|
6月前
|
设计模式 人工智能 安全
AQS:Java 中悲观锁的底层实现机制
AQS(AbstractQueuedSynchronizer)是Java并发包中实现同步组件的基础工具,支持锁(如ReentrantLock、ReadWriteLock)和线程同步工具类(如CountDownLatch、Semaphore)等。Doug Lea设计AQS旨在抽象基础同步操作,简化同步组件构建。 使用AQS需实现`tryAcquire(int arg)`和`tryRelease(int arg)`方法以获取和释放资源,共享模式还需实现`tryAcquireShared(int arg)`和`tryReleaseShared(int arg)`。
369 32
AQS:Java 中悲观锁的底层实现机制
|
7月前
|
Arthas 监控 Java
Arthas sc(查看JVM已加载的类信息 )
Arthas sc(查看JVM已加载的类信息 )
401 9
|
9月前
|
存储 缓存 算法
JDK11升级后竟让内存利用率飙升到90%以上?
JDK11升级后竟让内存利用率飙升到90%以上?
|
12月前
|
负载均衡 Java 持续交付
深入解析微服务架构中的服务发现与负载均衡
深入解析微服务架构中的服务发现与负载均衡
633 7
|
SQL XML Java
Mybatis的<where>,<if>等标签用法
这篇文章详细解释了Mybatis中<where>和<if>等标签的用法,展示了如何在SQL动态构建中有效地过滤条件和处理逻辑分支。
856 1
|
消息中间件 监控 供应链
深度剖析 RocketMQ 事务消息!
本文深入探讨了 RocketMQ 的事务消息原理及其应用场景。通过详细的源码分析,阐述了事务消息的基本流程,包括准备阶段、提交阶段及补偿机制。文章还提供了示例代码,帮助读者更好地理解整个过程。此外,还讨论了事务消息的优缺点、适用场景及注意事项,如确保本地事务的幂等性、合理设置超时时间等。尽管事务消息增加了系统复杂性,但在需要保证消息一致性的场景中,它仍是一种高效的解决方案。
1049 2
|
消息中间件 设计模式 安全
深入理解AQS队列同步器原理-从ReentrantLock的非公平独占锁实现来看AQS的原理
深入理解AQS队列同步器原理-从ReentrantLock的非公平独占锁实现来看AQS的原理
|
消息中间件 存储 监控
Kafka Streams:深度探索实时流处理应用程序
Apache Kafka Streams 是一款强大的实时流处理库,为构建实时数据处理应用提供了灵活且高性能的解决方案。本文将深入探讨 Kafka Streams 的核心概念、详细原理,并提供更加丰富的示例代码,以帮助大家深入理解和应用这一流处理框架。