📅  最后修改于: 2023-12-03 15:37:01.638000             🧑  作者: Mango
在字符串处理中,经常需要判断一个字符串是否包含另一个给定的字符串。本文将介绍如何计算一个字符串中包含另一个给定字符串作为子字符串的子字符串数量,以及如何找到这些子字符串。
最朴素的方法是枚举所有长度大于等于目标字符串长度的子串,判断是否包含目标字符串。具体实现过程中可以使用 indexOf()
函数来进行子串查找。
public static int countSubstring(String str, String target) {
int count = 0;
for (int i = 0; i <= str.length() - target.length(); i++) {
if (str.substring(i, i + target.length()).equals(target)) {
count++;
}
}
return count;
}
该算法的时间复杂度为 $O(n^2)$,其中 $n$ 表示字符串的长度,因为需要枚举所有子串并逐个比较。
KMP(Knuth–Morris–Pratt)算法是一种高效的字符串匹配算法,其时间复杂度为 $O(m+n)$,其中 $m$ 和 $n$ 分别为目标字符串和原字符串的长度。
该算法的基本思想是通过计算目标字符串的前缀函数(Prefix Function)来避免在进行匹配时反复回溯,从而减少匹配次数。
public static int countSubstring(String str, String target) {
int count = 0;
int[] prefix = getPrefix(target);
int j = 0;
for (int i = 0; i < str.length(); i++) {
while (j > 0 && str.charAt(i) != target.charAt(j)) {
j = prefix[j - 1];
}
if (str.charAt(i) == target.charAt(j)) {
j++;
}
if (j == target.length()) {
count++;
j = prefix[j - 1];
}
}
return count;
}
private static int[] getPrefix(String target) {
int[] prefix = new int[target.length()];
int j = 0;
for (int i = 1; i < target.length(); i++) {
while (j > 0 && target.charAt(i) != target.charAt(j)) {
j = prefix[j - 1];
}
if (target.charAt(i) == target.charAt(j)) {
j++;
}
prefix[i] = j;
}
return prefix;
}
该算法中,getPrefix()
函数用于计算目标字符串的前缀函数,countSubstring()
函数中 j 表示目标字符串和原字符串在当前位置匹配的长度。如果 j 等于目标字符串长度,则表示找到一个匹配,此时将 j 重置为前缀函数值即可。
以上两种算法都可以用于计算子字符串数量,但如果需要找到所有包含目标字符串的子串,则需要稍作修改。
public static List<String> findSubstring(String str, String target) {
List<String> result = new ArrayList<>();
int[] prefix = getPrefix(target);
int j = 0;
for (int i = 0; i < str.length(); i++) {
while (j > 0 && str.charAt(i) != target.charAt(j)) {
j = prefix[j - 1];
}
if (str.charAt(i) == target.charAt(j)) {
j++;
}
if (j == target.length()) {
result.add(str.substring(i - target.length() + 1, i + 1));
j = prefix[j - 1];
}
}
return result;
}
在计算子串数量的基础上,只需要在找到匹配字符串时调用 str.substring()
函数来截取子串即可。
本文介绍了两种算法用于计算一个字符串中包含另一个给定字符串作为子字符串的子字符串数量,以及如何找到这些子字符串。初学者可以先尝试使用 Brute Force 方法实现,而学习 KMP 算法则需要对字符串处理有一定的基础。