题目描述:
给定一个非空的字符串 s
,检查是否可以通过由它的一个子串重复多次构成。
子串不包括本身
思路:
1)主串和子串的问题,首先想到 KMP算法;可能讲不太清楚,但是掌握的内容足够说的尽量清楚;但是这道题后续的思维,不容易捋顺:
可用子串重复,子串最大长度为 n/2;一定是小于等于 n/2的;等于时很容易理解!
小于 n / 2时,其最后位置上的 next数值一定大于 n / 2;有一部分前后缀是重叠的;减去前缀剩下的一部分一定是 可重复的子串!
2)KMP算法中next数组的构建:while和for两种循环有所不同
for:
int size = s.length();
int[] next = new int[size];
int now = 0;//此时代表的也是 next[0]的值,此时为0
//注意 now的值和 数组下标的对应关系;now刚好是最大公共前后缀后一位的位置!
for(int i = 1;i < size;i++){//从一开始构造
if(s.charAt(i) == s.charAt(now)){
now++;//now后移
next[i] = now;
}
//此时不相同了,就是后缀长度不能加1;甚至一个都没有;要循环回去
else if(now != 0){
//直接在上一个位置的 最大前后缀的字符串里 往前找
now = next[now - 1];
//此时后面 i 不能加1
//使用 while和此不一样
i--;
}
else{
//此时往前找到了头now = 0;并且还不相等,就是首位都不相等
next[i] = now;
}
}
while:
int[] next = new int[p.length];
int now = 0;//其实就是第一个位置 index为0时,next数组的元素
int i = 1;
while(i < p.length){
//如果后缀加一,与前缀加一的位置相同,就在该位置的next 加以
if(p[i] == p[now]){
now++;
next[i] = now;
i++;
}
//如果加一不相等,且此时还没到最初的位置,则
else if(now != 0){
now = next[now - 1];
}
//如果已经到了头 就是p[i] != p[now] && now == 0
else{
next[i] = now;
i++;
}
}
代码:
1)KMP算法 + 思维的构建
class Solution {
public boolean repeatedSubstringPattern(String s) {
//next数组
int size = s.length();
int[] next = new int[size];
int now = 0;//此时代表的也是 next[0]的值,此时为0
//注意 now的值和 数组下标的对应关系;now刚好是最大公共前后缀后一位的位置!
for(int i = 1;i < size;i++){//从一开始构造
if(s.charAt(i) == s.charAt(now)){
now++;//now后移
next[i] = now;
}
//此时不相同了,就是后缀长度不能加1;甚至一个都没有;要循环回去
else if(now != 0){
//直接在上一个位置的 最大前后缀的字符串里 往前找
now = next[now - 1];
//此时后面 i 不能加1
//使用 while和此不一样
i--;
}
else{
//此时往前找到了头now = 0;并且还不相等,就是首位都不相等
next[i] = now;
}
}
//创建好了next数组
//本题的判断;如果存在重复字符串,前后缀表一定大于一半;且剩下的还能组成完整的字符串
if(next[size - 1] != 0 && size % (size - next[size - 1]) == 0) return true;
return false;
}
}
2)使用API;结合移动的思想;但是时间复杂度很高!
class Solution {
public boolean repeatedSubstringPattern(String s) {
String str = s + s;
return str.substring(1, str.length() - 1).contains(s);
}
}
作者:13217319563
链接:https://leetcode-cn.com/problems/repeated-substring-pattern/solution/jian-dan-ming-liao-guan-yu-javaliang-xing-dai-ma-s/
来源:力扣(LeetCode)