字串匹配:求乙個字串是不是另乙個字串的子串(下文稱為主串和模式串)
kmp能夠達到o(n+m)的時間複雜度,而暴力匹配(樸素匹配)則需要花費o(nm)的時間。
例題:判斷aaab是不是aabaaaab的子串
暴力匹配:
按順序乙個乙個匹配,失敗了重新開始(主串向前移動一位,模式串回到第一位)
重複這個動作,直到最後
匹配成功
****************************************=
kmp匹配
上述有冗餘的部分,即模式串每次匹配失敗都要回到第一位,主串也要回到和模式串第一位對應的位置,這就是複雜度o(nm)的原因。在匹配失敗時,能否利用已知的資訊,使得主串不用回滾,這樣就只遍歷主串一遍就能得出結果。方法是有的,這就是next陣列,next陣列說明了模式串每乙個位置的字元在匹配失敗時,當前匹配位置要回到之前的哪個地方。kmp的主要目的就是求出這個next陣列。
具體表現形式,上述匹配會出現這種情況
樸素匹配發生匹配錯誤,將主串和模式串的匹配位置回滾,下一步是這樣做
kmp發生匹配錯誤,通過next陣列知道要回到下標2的位置,主串不用回滾,所以下一步是這樣
也就是說它直接跳過前兩位的匹配,因為這兩位本來就是一樣的,為什麼還要再匹配一遍?
所以問題就轉到next陣列上,它為什麼知道要回到下標2的位置進行匹配,那我們就要知道這個next陣列是怎麼生成的。這有點像是乙個預處理的過程。
先說明兩個名詞,字串的字首和字尾,例如:
aaab的字首有:a,aa,aaa
aaab的字尾有:b,ab,aab
在最後乙個匹配失敗時,我們知道前面那些都是匹配上的,即相同的。
前面匹配上的那些又是模式串的內容,所以在前面找到最長的字首和字尾匹配,我們就可以把整塊挪過去,就不會是樸素匹配那樣乙個位置乙個位置挪。換句話說,next陣列的值就是(字首和字尾相同的最長長度)
紅色框就是完全匹配上的,綠色框也是完全相同的,所以下次匹配就是這樣子
這就是next陣列的原理,只要知道怎麼求字首字尾的相同的最大值,就能解決。
******************************====
雖然是說ac自動機=kmp+字典樹,但我看了ac自動機再回來看kmp挺清晰的。kmp就是乙個單節點的樹。
#include#include#includeusing namespace std;
const int n = 1000100;
int n, m;
// n 主串長度, m模式串長度
char a[n], b[n];
// a 主串, b 模式串, 下標從零開始
int nextt[n];
vectorans;
void get_nextt()
}void get_nextval()
else
}}int kmp_index(int pos)
else
}if(j >= m) return i-m;
else return -1;
}int kmp_count(int pos)
}else
j = nextt[j];
}return ans;
}int main()
for(int i=1;i<=m;i++)
return 0;
}
kmp字串匹配
首先要對模式串進行預處理。預處理過程就是計算出指定位置的字首和字尾的最大相同的長度 啊啊啊啊。估計只有我乙個人能看懂 這個文章說得很清楚 比如說 a a a c b c a a a 0 1 2 0 0 0 1 2 3 void getnext int next,char par 20 int n 翻...
字串匹配 KMP
參考 從頭到尾徹底理解kmp 在字串 str 中 匹配模式串 pattern 1.計算模式串的 next 陣列 2.在字串中匹配模式串 當乙個字元匹配時,str i pattern k 繼續匹配下乙個字元 當當前字元不匹配時,根據 next 陣列移動模式字串,k next k next 陣列 描述模...
KMP字串匹配
判斷s中是否含有字串t。一般思路為 從s中首字元開始,依次與t中進行比對,直到t結尾或者某乙個位置兩者不同 如果到t的結尾,則表示s中含有t。如果有乙個位置不相同,那麼從s中下乙個字元開始,再次與t中字元比對。如下 i 0,j 0 for i len 這樣的比較,每一次遇到不同的時候都需要從t串的第...