题目
在 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 两部分的位置,字符串的值不变。
证明
我们要证明的是: 如果一个字符串 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 变成下图所示
根据题设,我们将字符串首部的 A 交换到末尾的时候并不改变 S 的值,所以我们将 BA 式子的左侧的 A 依次都交换到末尾,变成如下图所示:
此时我们将多个连续的 A 看做是一个字符串,也就是 D=A...A,则可以将上面转移后的结果简化为下图所示:
也就是说 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,去除第一个和最后一个字符,再判断是否有子串的逻辑是可行的。