前言
到今天为止已经写完了数组、链表、哈希表、字符串的算法题,可以说是一波三折。万幸我挺过去了,接下来的就是更有挑战的栈与队列了,希望坚持住。
459.重复的子字符串
给定一个非空的字符串,判断它是否可以由它的一个子串重复多次构成。给定的字符串只含有小写英文字母,并且长度不超过10000。
示例 1:
输入: "abab"
输出: True
解释: 可由子字符串 "ab" 重复两次构成。
示例 2:
输入: "aba"
输出: False
示例 3:
输入: "abcabcabcabc"
输出: True
解释: 可由子字符串 "abc" 重复四次构成。 (或者子字符串 "abcabc" 重复两次构成。)
思路
这道题也涉及到了kmp算法,具体的实现这里就不说了,可以看我上一个文章,这道题的思路是:
当一个字符串s:abcabc,内部又重复的子串组成,那么这个字符串的结构一定是这样的:
也就是又前后又相同的子串组成。
那么既然前面有相同的子串,后面有相同的子串,用 s + s,这样组成的字符串中,后面的子串做前串,前后的子串做后串,就一定还能组成一个s,如图:
所以判断字符串s是否有重复子串组成,只要两个s拼接在一起,里面还出现一个s的话,就说明是又重复子串组成。
当然,我们在判断 s + s 拼接的字符串里是否出现一个s的的时候,要刨除 s + s 的首字符和尾字符,这样避免在s+s中搜索出原来的s,我们要搜索的是中间拼接出来的s。问题又变成了在一个字符串(s+s)中寻找另一个字符串(s),又可以使用kmp算法
代码
//这里我偷懒使用了原生的api
public boolean repeatedSubstringPattern(String s) {
String newString = s.substring(1,s.length())+s.substring(0,s.length()-1);
if (newString.contains(s)) {
return true;
}
return false;
}
//kmp
public boolean repeatedSubstringPattern(String s) {
if (s.equals("")) return false;
int len = s.length();
// 原串加个空格(哨兵),使下标从1开始,这样j从0开始,也不用初始化了
s = " " + s;
char[] chars = s.toCharArray();
int[] next = new int[len + 1];
// 构造 next 数组过程,j从0开始(空格),i从2开始
for (int i = 2, j = 0; i <= len; i++) {
// 匹配不成功,j回到前一位置 next 数组所对应的值
while (j > 0 && chars[i] != chars[j + 1]) j = next[j];
// 匹配成功,j往后移
if (chars[i] == chars[j + 1]) j++;
// 更新 next 数组的值
next[i] = j;
}
// 最后判断是否是重复的子字符串,这里 next[len] 即代表next数组末尾的值
if (next[len] > 0 && len % (len - next[len]) == 0) {
return true;
}
return false;
}
注意
这道题主要是将两个字符串拼接后,中间一定存在新的原字符串
字符串,双指针
太多了,根本写不下来,就算写下来后思路也不连贯。还是看卡哥的代码随想录复习吧。
总结
快到期中了,有一些课要结业了,时间又紧了,我八股文,面试题,微服务,项目都还没进入状态,哎,加油吧,做好现在应该做的,时间会给我回报的。