力扣28 实现strStr()
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/36fcb7d84accd212be1c7497dfa934d3.png)
LPS[len - 1] 记录的是橘色字符串的最长的前缀和后缀,假如 LPS[len - 1]=3,那么前面 3 个字符和后面的 3 个字符相等
绿色的部分其实和橘色的部分相同。
LPS[len - 1] 记录的其实是 i 指针之前的字符串里的第二长的公共前缀和后缀(最关键点)。
更新 len = LPS[len - 1],继续比较 needle[i] 和 needle[len]。
class Solution {
public int strStr(String haystack, String needle) {
int m = haystack.length(), n = needle.length();
if(n == 0){
return 0;
}
// 暴力求解
// for(int i = 0; i < m; ++i) {
// int k = i, j;
// if(i + n > m) { return -1;}
// for(j = 0; j < n; ++j) {
// if(haystack.charAt(k++) != needle.charAt(j)){
// break;
// }
// }
// if(j == n) { return i;}
// }
// KMP求解 O(m+n)
int[] lps = getLps(needle); //获得LPS数组
int i = 0, j = 0;
while(i < m) {
if(haystack.charAt(i) == needle.charAt(j)) {
i++; j++;
if(j == n) {
return i - n;
}
} else if(j > 0) {
// haystack = "ABC ABCDAB ABCDABCDABDE"
// needle = "ABCDABD" //j = 6
// j = lps[6 - 1] = 2; 下一次直接从needle[2]开始比较,实现跳跃->
// haystack = "ABC ABCDAB ABCDABCDABDE"
// needle = "ABCDABD"
j = lps[j - 1];
} else if(j == 0){
i++; //首字母都不相同,直接右移比较下一个字母
}
}
return -1;
}
int[] getLps(String needle) {
int n = needle.length();
int[] lps = new int[n]; //初始化全为0
// 规定自身不算公共子串,lps[0] = 0, 直接从lps[1]开始
int i = 1, len = 0;
while(i < n) {
if(needle.charAt(i) == needle.charAt(len)) {
lps[i++] = ++len; //lps[i] = len + 1, i = i + 1;
} else if(len > 0) {
len = lps[len - 1]; // 如果len > 0,尝试第二长的前缀与后缀,看是否能延续下去
} else if(len == 0) {
i++; // 所有的前缀和后缀都不符合,则lps[i] = 0;(因为初始化都为0,不用再赋值) i++;
}
}
return lps;
}
}