KMP算法

28. 实现 strStr()

28. 实现 strStr() 459.重复的子字符串_i++

class Solution {
public int strStr(String haystack, String needle) {
if(needle.length() == 0) return 0;
int[] next = new int[needle.length()];
getNext(next,needle);
int j = 0;
for(int i = 0;i < haystack.length();i++){
while(j > 0 && haystack.charAt(i) != needle.charAt(j)){
j = next[j - 1];
}
if(haystack.charAt(i) == needle.charAt(j)) j++;
if(needle.length() == j){
return i - j + 1;
}
}
return -1;
}
void getNext(int[] next, String needle){
int j = 0;
next[0] = j;
for(int i = 1;i < needle.length();i++){
while(j > 0 && needle.charAt(i) != needle.charAt(j)){
j = next[j - 1];
}
if(needle.charAt(i) == needle.charAt(j)){
j++;
}
next[i] = j;
}
}
}

28. 实现 strStr() 459.重复的子字符串_java_02

459.重复的子字符串

28. 实现 strStr() 459.重复的子字符串_字符串_03


方法一:移动匹配法:

28. 实现 strStr() 459.重复的子字符串_算法_04


将两个相同字符串拼接,拼接后的字符串如果还出现当时的字符串,那么就说明存在重复的子字符串,需要去除字符串的首尾字符来避免刚开始或者结束的字符串中匹配到。

class Solution {
public boolean repeatedSubstringPattern(String s) {
String t = s + s;
StringBuilder sb = new StringBuilder(t);
sb.deleteCharAt(0);
sb.deleteCharAt(sb.length() - 1);
System.out.println(sb.toString());
return sb.toString().contains(s);
}
}

28. 实现 strStr() 459.重复的子字符串_java_05


方法二:kmp法

28. 实现 strStr() 459.重复的子字符串_算法_06


数组长度减去最长相同前后缀的长度相当于是第一个周期的长度,也就是一个周期的长度,如果这个周期可以被整除,就说明整个数组就是这个周期的循环。

28. 实现 strStr() 459.重复的子字符串_java_07

class Solution {
public boolean repeatedSubstringPattern(String s) {
int len = s.length();
char[] ch = s.toCharArray();
int[] next = new int[len];
int j = 0;
for(int i = 1;i < s.length();i++){
while(j > 0 && ch[i] != ch[j]){
j = next[j - 1];
}
if(ch[i] == ch[j]) j++;
next[i] = j;
}
// 最后判断是否是重复的子字符串
if(next[len - 1] > 0 && (len % (len - next[len - 1])) == 0) {
return true;
}
return false;
}
}

28. 实现 strStr() 459.重复的子字符串_算法_08