https://www.bilibili.com/video/BV1jb411V78H/?spm_id_from=333.337.search-card.all.click&vd_source=bde90da16f250a6e50477a7d2d583283
关键:最长相同前后缀
class Solution {
public:
int strStr(string haystack, string needle) {
int n = haystack.size(), m = needle.size();
if (m == 0) {
return 0;
}
vector<int> next(m);
for (int i = 1, j = 0; i < m; i++) {
//其中i指向后缀的末尾,j指向前缀的末尾
// 不匹配,遇见冲突,看前一位的相同前缀的位
//例子"abcabd abcabd abcaaa"
//next数组为next:{0, 0, 0, 1, 2, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 4, 1}
//在最后的abca a a中,后缀末尾的a与当前j指向的前缀末尾不匹配,所以前缀j要向前回退
//如果直接将j退到0,则不是一个好的方法, 可能会忽略掉前面已有的相同前后缀
//之前的最长相同前缀1为abc abd abc
// 后缀1 abc abd abc
//这里面是否也存在某个相同前后缀
//前后缀是相同的,在前缀中再找到一个相同前后缀即可,就是j移动的位置
//此时存在abc abd abc存在一个相同前后缀
//即前缀2 abc
// 后缀2 abc
//则前缀1中的前后缀2,也会存在与后缀2中,
//且前缀的前缀的下一个字符 needle[j]==needle[i]=a,这时的i还指向整个循环的后缀
while (j > 0 && needle[i] != needle[j]) {
j = next[j - 1];
}
if (needle[i] == needle[j]) {
j++;
}
pi[i] = j;
}
for (int i = 0, j = 0; i < n; i++) {
while (j > 0 && haystack[i] != needle[j]) {
j = next[j - 1];
}
if (haystack[i] == needle[j]) {
j++;
}
if (j == m) {
return i - m + 1;
}
}
return -1;
}
};