kmp演算法是乙個效率很高的字串匹配演算法。
我們先看一下樸素的字串匹配演算法,將模式串的每一位與原串進行匹配,如果發生失配現象,則要將原串向前挪一位,以此類推,直到匹配成功為止,設模式串的長度為n,原串的長度為m,則匹配的時間複雜度為o(nm),kmp演算法改進了失配後的操作,引進了next陣列,加速了匹配,使字串匹配的速度變成了線性o(n+m)。
假設我們匹配的過程中出現了這麼一種情況,
在kmp演算法中,此時會呼叫next陣列,那麼next陣列是記錄什麼的呢?
next陣列是記錄模式串前i位字首和字尾的最長公共長度。
假設我們現在匹配到了第i位,我們分析移位前後的模式串f有什麼變化,得到如下結論。
所以前移k位之後,可以繼續比較位置i的前提是f的前i-1個位置滿足:
長度為i-k-1的字首a和字尾b相同
。只有這樣,我們才可以前移k位後從新的位置繼續比較。
所以kmp演算法的核心是計算字串f每乙個位置之前的字首和字尾最長公共部分(不計算字串本身),獲得模式串f每乙個位置的最大公共長度後,就可以利用該最大長度與原串o進行比較,當每次比較到兩個字串的字元不同時,我們就可以根據最大公共長度將字串f向前移動(已匹配長度-最大公共長度)位,接著繼續比較下乙個位置。事實上,字串f的前移只是概念上的前移,只要我們在比較的時候從最大公共長度之後比較f和o即可達到字串f前移的目的。
理解了kmp演算法的基本原理,下一步就是要獲得字串f每乙個位置的最大公共長度。這個最大公共長度在演算法導論裡面被記為next陣列。
在這裡要注意一點,
next
陣列表示的是長度,下標從
1開始;但是在遍歷原字串時,下標還是從
0開始。
假設我們現在已經求得 next[1],next[2],next[3]...next[i],分別表示長度為1到i的字串的字首和字尾最長公共部分的長度現在要求next[i+1],如果位置i和位置next[i]處的兩個字元相同(
下標從零開始
),則next[i+1]等於next[i]加1。如果兩個位置的字元不相同,我們可以將長度為next[i]的字串繼續分割,獲得其最大公共長度next[next[i]],然後再和位置i的字元比較。這是因為長度為next[i]字首和字尾都可以分割成上部的構造,如果位置next[next[i]]和位置i的字元相同,則next[i+1]就等於next[next[i]]加1。如果不相等,就可以繼續分割長度為next[next[i]]的字串,直到字串長度為0為止。
void cal_next(char str,int next,int len)
}
計算完next陣列後,我們可以利用next陣列在字串o中找到字串f出現的位置,匹配的**和求next陣列非常相似。
如果匹配上了,就往後推一位,否則挪動公共的字首到字尾處再進行匹配
int kmp( char str, int slen, char ptr, int plen, int next )
else
}return ( p_i == plen ) ? ( s_i - plen ) : -1;
}
字串匹配演算法 BF及KMP
以 absababcef 與 abce 為例,求串2與串1匹配的第乙個位置的下標 這裡即輸出 5 一般的,我們可以從串1的起始位置開始與串2比較,若相同則兩串都向後移,否則,串1回到第二個位置,串2回到起始位置重新比較。本題用此方法會超時 includeint a 10001 b 10001 int...
KMP演算法 字串匹配
kmp演算法基本思想 我們在用常規的思想做 字串匹配時候是 如 對如 字元如果 t abab 用p ba 去匹配,常規思路是 看 t 第乙個元素 a 是否 和p 的乙個 b 匹配 匹配的話 檢視各自的第二個元素,不匹配 則將 t 串的 第二個元素開始 和 p 的第乙個匹配,如此 一步一步 的後移 來...
KMP字串匹配演算法
kmp核心思想 計算模式串的next陣列,主串的索引在比較的過程中不回朔 ifndef kmp h define kmp h class kmp endif include kmp.h include include include using namespace std int kmp calcu...