百度發現很多答案都是錯誤的,全是相互抄襲,也不經過驗證就放出來,這裏提供正確的搜索算法。
方案一,使用KMP算法,KMP算法是一種改進的字符串匹配算法,由D.E.Knuth,J.H.Morris和V.R.Pratt提出的,因此人們稱它爲克努特—莫里斯—普拉特操作(簡稱KMP算法)。KMP算法的核心是利用匹配失敗後的信息,儘量減少模式串與主串的匹配次數以達到快速匹配的目的。具體實現就是通過一個next()函數實現,函數本身包含了模式串的局部匹配信息。KMP算法的時間複雜度O(m+n)。
代碼實現:
public class KMPSearcher {
public static int KMPSearch(String pat, String txt) {
int M = pat.length();
int N = txt.length();
// create lps[] that will hold the longest
// prefix suffix values for pattern
int lps[] = new int[M];
int j = 0; // index for pat[]
// Preprocess the pattern (calculate lps[]
// array)
computeLPSArray(pat, M, lps);
int i = 0; // index for txt[]
int res = 0;
int next_i = 0;
while (i < N) {
if (pat.charAt(j) == txt.charAt(i)) {
j++;
i++;
}
if (j == M) {
// When we find pattern first time,
// we iterate again to check if there
// exists more pattern
j = lps[j - 1];
res++;
// We start i to check for more than once
// appearance of pattern, we will reset i
// to previous start+1
if (lps[j] != 0) {
i = ++next_i;
}
j = 0;
}
// mismatch after j matches
else if (i < N && pat.charAt(j) != txt.charAt(i)) {
// Do not match lps[0..lps[j-1]] characters,
// they will match anyway
if (j != 0) {
j = lps[j - 1];
} else {
i = i + 1;
}
}
}
return res;
}
private static void computeLPSArray(String pat, int M, int lps[]) {
// length of the previous longest prefix suffix
int len = 0;
int i = 1;
lps[0] = 0; // lps[0] is always 0
// the loop calculates lps[i] for i = 1 to M-1
while (i < M) {
if (pat.charAt(i) == pat.charAt(len)) {
len++;
lps[i] = len;
i++;
} else // (pat[i] != pat[len])
{
// This is tricky. Consider the example.
// AAACAAAA and i = 7. The idea is similar
// to search step.
if (len != 0) {
len = lps[len - 1];
// Also, note that we do not increment
// i here
} else // if (len == 0)
{
lps[i] = len;
i++;
}
}
}
}
}
方案二,字符串從左到右逐一匹配
public class StringCounter {
public static int countFreq(String pat, String txt) {
int M = pat.length();
int N = txt.length();
int res = 0;
/* A loop to slide pat[] one by one */
for (int i = 0; i <= N - M; i++) {
/* For current index i, check for
pattern match */
int j;
for (j = 0; j < M; j++) {
if (txt.charAt(i + j) != pat.charAt(j)) {
break;
}
}
// if pat[0...M-1] = txt[i, i+1, ...i+M-1]
if (j == M) {
res++;
j = 0;
}
}
return res;
}
}
測試結果:
int count = KMPSearcher.KMPSearch("aa", "aaaa");
System.out.println(count);
int count1 = StringCounter.countFreq("aa", "aaaa");
System.out.println(count1);
均輸出 3 。
參考文檔:https://www.geeksforgeeks.org/frequency-substring-string/