重复子字符串算法证明

2 篇文章 0 订阅
1 篇文章 0 订阅

题目

在 leetcode 上面有这样一个题目:

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

大家有空的时候,可以去尝试做下这道题目。


题目链接:https://leetcode.cn/problems/repeated-substring-pattern/


题解


class Solution {
    public boolean repeatedSubstringPattern(String s) {
        String t=(s+s);
        return t.substring(1,t.length()-1).contains(s);
    }
}



官方的解释没有看懂,所以自己证明下其中不明白的地方。

代码确认的信息

我们把两个字符串相连,然后去除第一位和最后一位,然后判断s 是否是新字符串的子串,这几步的操作最终得到的是这样一个信息:

字符串 s 可以分成两部分 A 和 B,交换 A 和 B 两部分的位置,字符串的值不变。

a5e14473a57ad2e81fbb1f051e069c2c.jpeg

证明

我们要证明的是: 如果一个字符串 S 可以分成两个部分,交换这两个部分,可以得到相同的字符串 S,那么一定存在一个字符串 T,重复 n 次 T,就可以得到 S,或者说 S 可以通过它的一个子串重复多次构成。

如果 A 和 B 的长度相等,根据题设则有 A==B,此时 S 可以由 A 来重复两次构成。
如果 A 的长度大于 B,我们可以交换 A 和 B 的位置和名称,使得 A 的长度小于 B 的长度,转换为第三种情形。
如果 A 的长度小于 B,此时我们可以把 B 再次进行分解,B=A...AC,其中A共有n个,C.length < A.length
第一种和第二种都可以证明我们的题设,但是第三种并不能,现在我们来讨论第三种情形。

将 S 中 B 替换后, AB 和 BA 变成下图所示

158a5050c7d5be2392616c321aec65c7.jpeg
根据题设,我们将字符串首部的 A 交换到末尾的时候并不改变 S 的值,所以我们将 BA 式子的左侧的 A 依次都交换到末尾,变成如下图所示:

23882dd8dc6f98b9c2c67b8eaf6c5644.jpeg
此时我们将多个连续的 A 看做是一个字符串,也就是 D=A...A,则可以将上面转移后的结果简化为下图所示:

ea56d22994be2d1867ad3f1c899f4ac3.jpeg
也就是说 S==CD==DC,可以观察到,我们又得到了形如题设的等式 S==AB==BA,不同的是 C.length < A.length,也就是说,虽然等式形式上相同但是左侧的部分的长度在衰减。

按照上面的思路继续重复上面的证明过程,即使每轮证明我们都会进入第三种情形,但是我们终将得到一个等式 S==XY=YX,其中 X.length==1,此时不断将第一个字符放到末尾,S 不变,就可以证明 S 中所有的字符都相同。

一个由单个字符构成的 S ,明显可以通过它的一个子串(任意单个字符的子串)重复多次构成。

证明完毕!

结论

如果一个字符串 S 可以分成两个部分,交换这两个部分,可以得到相同的字符串 S,那么一定存在一个字符串 T,重复 n 次 T,就可以得到 S,或者说 S 可以通过它的一个子串重复多次构成。

所以我们构造两个s,去除第一个和最后一个字符,再判断是否有子串的逻辑是可行的。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

m0_37657276

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值