思路
(KMP) $O(n+m)$
具体过程如下:
next[i]
记录子串ha[1, 2, , , i - 1, i]
的最长相等前后缀的前缀最后一位下标,或者说是子串的最长相等前后缀的长度。- 预处理出
next
数组。 - 遍历字符串
ha
:
● 当ha
字符串和ne
字符串发生失配时,根据next
数组回退到其他位置。
● 当匹配ne
字符串的终点时,用匹配终点i
减去字符串ne
的长度m
即是答案。
KMP核心思路如下图所示:
时间复杂度分析: KMP 算法的时间复杂度为 $O(n+m)$。
C++代码
class Solution {
public:
int strStr(string ha, string ne) {
int n = ha.size(), m = ne.size();
if(m == 0) return 0;
vector<int> next(m + 1);
ha = ' ' + ha ,ne = ' ' + ne;
for(int i = 2, j = 0; i <= m; i++){
while(j && ne[i] != ne[j + 1]) j = next[j];
if(ne[i] == ne[j + 1]) j++;
next[i] = j;
}
for(int i = 1, j = 0; i <= n; i++){
while(j && ha[i] != ne[j + 1]) j = next[j];
if(ha[i] == ne[j + 1]) j++;
if(j == m){
return i - m;
}
}
return -1;
}
};
Java代码
class Solution {
public int strStr(String ha, String ne) {
if (ha.isEmpty()) return 0;
int n = ha.length(), m = ne.length();
ha = " " + ha;
ne = " " + ne;
int[] next = new int[m + 1];
for (int i = 2, j = 0; i <= m; ++i) {
while (j > 0 && ne.charAt(i) != ne.charAt(j + 1)) j = next[j];
if (ne.charAt(i) == ne.charAt(j + 1)) j++;
next[i] = j;
}
for (int i = 1, j = 0; i <= n; ++i) {
while (j > 0 && ha.charAt(i) != ne.charAt(j + 1)) j = next[j];
if (ha.charAt(i) == ne.charAt(j + 1)) j++;
if (j == m) {
return i - m;
}
}
return -1;
}
}
Go代码
func strStr(ha string, ne string) int {
if len(ne) == 0 {
return 0
}
n, m := len(ha), len(ne)
ha, ne = " " + ha, " " + ne
next := make([]int, m + 1)
for i, j := 2, 0; i <= m; i++ {
for j > 0 && ne[i] != ne[j + 1] {
j = next[j]
}
if ne[i] == ne[j+1] {
j++
}
next[i] = j
}
for i, j := 1, 0; i <= n; i++ {
for j > 0 && ha[i] != ne[j + 1] {
j = next[j]
}
if ha[i] == ne[j + 1] {
j++
}
if j == m {
return i - m
}
}
return -1
}