實現 strStr(haystack, needle):返回 needle 在 haystack 中首次出現的索引,不存在返回 -1。空 needle 返回 0。
對每個起始位置嘗試匹配,失敗則回退。LeetCode 測試數據會 TLE。
needle 哈希值 H_needlehaystack 長度 M 子串哈希 H_winH_win = (H_win - haystack[i-M]*B^{M-1}) * B + haystack[i]class Solution {
static constexpr int BASE = 131;
static constexpr long long MOD = 1e9+7; // 可選,防溢出
int charVal(char c) { return c - 'a' + 1; } // 假設小寫字母
public:
int strStr(string haystack, string needle) {
int n = haystack.size(), m = needle.size();
if (m == 0) return 0;
if (m > n) return -1;
long long hashN = 0, hashH = 0, power = 1;
for (int i = 0; i < m; ++i) {
hashN = (hashN * BASE + charVal(needle[i])) % MOD;
hashH = (hashH * BASE + charVal(haystack[i])) % MOD;
if (i < m-1) power = (power * BASE) % MOD;
}
if (hashH == hashN && haystack.substr(0, m) == needle) return 0;
for (int i = m; i < n; ++i) {
hashH = (hashH - charVal(haystack[i-m]) * power % MOD + MOD) % MOD;
hashH = (hashH * BASE + charVal(haystack[i])) % MOD;
if (hashH == hashN && haystack.substr(i-m+1, m) == needle)
return i - m + 1;
}
return -1;
}
};
next[i] = 模式串 needle[0..i] 的最長真前綴同時為後綴的長度。
vector<int> buildNext(const string& p) {
int m = p.size();
vector<int> nxt(m, 0);
for (int i = 1, j = 0; i < m; ++i) {
while (j > 0 && p[i] != p[j]) j = nxt[j-1];
if (p[i] == p[j]) ++j;
nxt[i] = j;
}
return nxt;
}
int strStr(string haystack, string needle) {
if (needle.empty()) return 0;
auto nxt = buildNext(needle);
for (int i = 0, j = 0; i < (int)haystack.size(); ++i) {
while (j > 0 && haystack[i] != needle[j]) j = nxt[j-1];
if (haystack[i] == needle[j]) ++j;
if (j == (int)needle.size()) return i - j + 1;
}
return -1;
}
| 算法 | 時間 | 空間 | 備註 |
|---|---|---|---|
| 暴力 | O(MN) | O(1) | 簡單但慢 |
| Rabin-Karp | O(N+M) 期望 | O(1) | 需處理哈希碰撞 |
| KMP | O(N+M) 最壞 | O(M) | 確定性,面試首選 |