1. 前后缀都是从左往右读
2. 前缀是不包含最后一个字符的所有以第一个字符为开头的子串的集合
后缀是不包含第一个字符的所有以最后一个字符为结尾的子串的集合
3. j = next[j] // 回跳
回跳指前缀末尾指针 j + 1 返回到 substr[0, j] 的最长相同前缀的后一个字符,因为模式串中的最 长相同前缀已经和文本串中 i 指针前面的若干个字符匹配了
void getNext(int* next, const string& str) {
int j = -1;
next[0] = j;
const int size = str.size();
for (int i = 1; i < size; i++) { // warning: i 从 1 开始
while (j >= 0 && str[j + 1] != str[i]) j = next[j]; // 前后缀末尾不同则 j 指针回跳
if (str[j + 1] == str[i]) j++; // 前后缀末尾相同则 j 指针++
next[i] = j; // 记录 i 位置的最长相同前后缀的长度
}
}
class Solution {
public:
int strStr(string haystack, string needle) {
int* next = new int[needle.size()];
getNext(next, needle);
const int sizeHay = haystack.size();
const int sizeNeedle = needle.size();
int j = -1;
for (int i = 0; i < sizeHay; i++) {
while (j >= 0 && haystack[i] != needle[j + 1]) j = next[j];
if (haystack[i] == needle[j + 1]) j++;
if (j == sizeNeedle - 1) return (i - sizeNeedle + 1);
}
return -1;
}
};