594 · 字符串查找 II
困难 | 30% 通过率 | 要求 O(n + m)
→ 标准「KMP 模板题」。
继续用「快刷四部曲」5 分钟背完、一辈子会用。
第一步:识别模式
- 题型:单模式串精确匹配
- 模式:KMP(Knuth--Morris--Pratt)
- 关键 :预处理
next[]数组,失配时 不回退主串指针 - 复杂度 :预处理 O(m) + 匹配 O(n) = O(n + m),空间 O(m)
第二步:选择模板
KMP 双函数固定写法:
buildNext(String p)→ 返回next[]strStr(String s, String p)→ 返回首位置或 -1
第三步:注意边界
- 空模式串:约定返回 0(与 Java 内置
indexOf一致) - 主串长度 n、模式串长度 m,m > n 时直接 -1
next[]长度 = m,next[0] = -1(经典 -1 写法最简洁)
第四步:成功秒杀(完整代码)
java
public class Solution {
/**
* @param source: the source string
* @param target: the target string
* @return: the first index of target in source, or -1 if not exist
*/
public int strStr(String source, String target) {
if (target == null || source == null) return -1;
int n = source.length(), m = target.length();
if (m == 0) return 0; // 空模式串约定返回 0
if (m > n) return -1; // 剪枝
int[] next = buildNext(target);
int i = 0, j = 0; // i 指向 source,j 指向 target
while (i < n) {
if (j == -1 || source.charAt(i) == target.charAt(j)) {
i++; j++;
} else {
j = next[j]; // 失配,j 回退
}
if (j == m) { // 完全匹配
return i - j;
}
}
return -1;
}
// 预处理 next 数组,next[0] = -1
private int[] buildNext(String p) {
int m = p.length();
int[] next = new int[m];
next[0] = -1;
int i = 0, j = -1;
while (i < m - 1) {
if (j == -1 || p.charAt(i) == p.charAt(j)) {
i++; j++;
next[i] = j;
} else {
j = next[j];
}
}
return next;
}
}
复杂度
- 时间:O(n + m)
- 空间 :O(m) 仅
next[]
背下 buildNext + strStr 双函数,以后任何「单模式串匹配」困难题直接秒。