力扣第 28 题:实现 strStr() 的 3 种思路,让你秒懂!
2023-11-08 01:34:20
剖析力扣第 28 题:掌握字符串匹配算法
引言
字符串匹配是软件开发中一项必不可少的技能。力扣第 28 题要求我们实现 strStr()
函数,以找出给定字符串 haystack
中子串 needle
的首次出现位置。
暴力匹配:简单易懂
暴力匹配是一种直接比较 haystack
和 needle
字符串的朴素方法。这种方法易于理解,但时间复杂度为 O(m * n),其中 m 和 n 分别是 haystack
和 needle
的长度。
// 暴力匹配 Java 代码
public int strStr(String haystack, String needle) {
if (needle.isEmpty()) {
return 0;
}
int n = needle.length();
for (int i = 0; i <= haystack.length() - n; i++) {
if (haystack.substring(i, i + n).equals(needle)) {
return i;
}
}
return -1;
}
KMP 算法:预处理提升效率
KMP 算法(Knuth-Morris-Pratt 算法)通过预处理 needle
字符串,建立一个称为 next 数组的信息表,从而优化匹配过程。next 数组存储了每个 needle
字符后缀与 needle
本身的最长公共前缀的长度。这种预处理有助于算法在遇到不匹配时快速跳过不必要的比较,从而将时间复杂度降低到 O(m + n)。
// KMP 算法 Java 代码
public int strStr(String haystack, String needle) {
if (needle.isEmpty()) {
return 0;
}
int[] next = getNext(needle);
int i = 0;
int j = 0;
while (i < haystack.length() && j < needle.length()) {
if (j == -1 || haystack.charAt(i) == needle.charAt(j)) {
i++;
j++;
} else {
j = next[j];
}
}
return j == needle.length() ? i - j : -1;
}
private int[] getNext(String needle) {
int[] next = new int[needle.length()];
next[0] = -1;
int i = 0;
int j = -1;
while (i < needle.length() - 1) {
if (j == -1 || needle.charAt(i) == needle.charAt(j)) {
next[++i] = ++j;
} else {
j = next[j];
}
}
return next;
}
Boyer-Moore 算法:坏字符与好后缀
Boyer-Moore 算法通过分析 needle
字符串的特征来优化匹配过程。它维护一个 last 数组,其中存储了每个字符在 needle
字符串中的最后出现位置。该算法在遇到不匹配时利用 last 数组快速跳过不必要的比较,同时还考虑了 needle
字符串的 "好后缀" 特性,进一步提升了效率。
// Boyer-Moore 算法 Java 代码
public int strStr(String haystack, String needle) {
if (needle.isEmpty()) {
return 0;
}
int[] last = getLast(needle);
int n = needle.length();
int i = n - 1;
while (i < haystack.length()) {
int j = n - 1;
while (j >= 0 && needle.charAt(j) == haystack.charAt(i)) {
j--;
i--;
}
if (j == -1) {
return i + 1;
} else {
i += n - 1 - last[haystack.charAt(i)];
}
}
return -1;
}
private int[] getLast(String needle) {
int[] last = new int[256];
for (int i = 0; i < 256; i++) {
last[i] = -1;
}
for (int i = 0; i < needle.length(); i++) {
last[needle.charAt(i)] = i;
}
return last;
}
总结:选择适合的算法
暴力匹配简单易懂,适合小规模字符串匹配场景。KMP 算法和 Boyer-Moore 算法高效快速,适用于处理大规模字符串匹配问题。在实际应用中,根据具体情况选择合适的方法尤为重要。
常见问题解答
-
什么是字符串匹配算法?
- 字符串匹配算法是一种计算机程序,用于在一个大字符串中寻找一个较小字符串的出现位置。
-
为什么字符串匹配在软件开发中很重要?
- 字符串匹配算法广泛应用于搜索引擎、文本编辑器和数据库查询等各种软件开发领域。
-
KMP 算法和 Boyer-Moore 算法有什么优势?
- 这些算法通过预处理和优化比较过程,实现了比暴力匹配更快的匹配速度。
-
什么时候应该使用暴力匹配算法?
- 当字符串较小时,暴力匹配算法通常是最简单的选择。
-
如何选择最佳的字符串匹配算法?
- 根据字符串长度、匹配频率和应用程序性能要求来选择算法。