字符串匹配中常常會用到KMP算法。它求解的問題類型是:字符串匹配。給你兩個字符串,尋找其中一個字符串是否包含另外一個字符串,若是包含,返回包含的起始位置。 ios
咱們通常的作法是:將一個字符串(長度爲n,模式串)放在另外一個字符串(長度爲m,主串)開始的位置,而後依次比較,若是有不匹配的字符,就將字符串日後移一位,而後依舊從頭開始比較。直到找到徹底匹配的位置,返回。遍歷順序從0到m-n,每次遍歷,都要比較n(最多)次,因此複雜度近似爲O(m*n);算法
而咱們今天說的這個KMP算法,能夠達到O(m+n)的複雜度。數組
算法基本思想:每次當匹配失敗時,沒有必要就移動一位,由於前面可能有已經匹配的字符了。若是模式串當前的字符存在公共先後綴,那麼我能夠對於每個模式串事先計算出模式串的內部匹配信息,在匹配失敗時最大的移動模式串,以減小匹配次數。spa
注意最長前綴:是說以第一個字符開始,可是不包含最後一個字符code
KMP有個next數組,用來存放模式串中內部的匹配信息。舉個例子,好比模式串爲ababaca,長度是7,因此next[0],next[1],next[2],next[3],next[4],next[5],next[6]分別計算的是 a,ab,aba,abab,ababa,ababac,ababaca的相同的最長前綴和最長後綴的長度。因爲a,ab,aba,abab,ababa,ababac,ababaca的相同的最長前綴和最長後綴是「」,「」,「a」,「ab」,「aba」,「」,「a」,因此next數組的值是[-1,-1,0,1,2,-1,0],這裏-1表示不存在,0表示存在長度爲1,2表示存在長度爲3。這是爲了和代碼相對應。blog
當求出模式串的next數組以後,咱們就要進行KMP算法的匹配了。ci
#include <iostream> #include <string> #include <vector> using namespace std; void cal_next(string str,vector<int>&next) { int len=str.size(); next[0]=-1; int k=-1; for(int i=1;i<len;i++) { while(k>-1 && str[k+1]!=str[i]) { k=next[k]; } if(str[k+1]==str[i]) { k++; } next[i]=k; } } int KMP(string str,string ptr,vector<int>&next) { int s=0,p=0; while(s<str.size() && p<ptr.size()) { if(str[s]==ptr[p]) { s++; p++; } else { if(p==0) s++; else p=next[p-1]+1; } } return (p==ptr.size())?(s-ptr.size()):-1; } int main() { string str,ptr; cin>>str>>ptr; vector<int> next; next.resize(ptr.size(),0); cal_next(ptr,next); cout<<KMP(str,ptr,next)<<endl; return 0; }
程序的關鍵在於如何理解next的做用,以及如何維護它。字符串