題目描述
給你兩個字串 haystack 和 needle ,請你在 haystack 字串中找出 needle 字串的第一個匹配項的下標(下標從 0 開始)。如果 needle 不是 haystack 的一部分,則返回 -1 。
-
示例 1:
輸入:haystack = "sadbutsad", needle = "sad"
輸出:0
解釋:"sad" 在下標 0 和 6 處匹配。
第一個匹配項的下標是 0 ,所以返回 0 。 -
示例 2:
輸入:haystack = "leetcode", needle = "leeto"
輸出:-1
解釋:"leeto" 沒有在 "leetcode" 中出現,所以返回 -1 。 -
提示:
1 <= haystack.length, needle.length <= 104 haystack 和 needle 僅由小寫英文字元組成
KMP演算法
字串匹配問題,設主串有m個字元,模式串有n個字元,暴力方法要時間O(mn)。KMP演算法透過求解next陣列,消除了失配時主串回溯步驟,使得時間複雜度降低到O(m+n)。
核心 —— next/nextval陣列
當haystack[p]和needle[q]失配發生時,主串指標p不動,模式串指標q跳轉到nextval[q]與主串匹配。
分析模式串,求解next/nextval陣列
-
先求next陣列
next[i] = needle[0..i]的最長匹配前字尾的長度;
-
推導nextval陣列
nextval[0] = -1;
nextval[i] = next[i-1]; -
也可以一步到位,比如這個實現
vector<int> nextval(n, 0); nextval[0] = -1; // -1表示下一匹配中,主串指標p++, 模式串指標q=0 for(int j = 0, k = -1; j < n - 1; ) { if(k == -1 || needle[j] == needle[k]) { ++k, ++j; nextval[j] = k; } else { k = next[k]; // point } }
匹配,返回第一次匹配模式串的下標
int p = 0, q = 0;
while(q < n && p < m) {
if(haystack[p] == needle[q]) {
++p, ++q;
} else {
if(nextval[q] == -1) {
++p;
q = 0;
} else {
q = nextval[q];
}
}
}
if(q == n) {
return p - n;
} else {
return -1;
}