(假設各位不會什麼字串雜湊)
對於子串查詢這類問題,如果我單純詢問乙個字串s1中出現了多少次s2,暴力方法很好想,直接固定起點向後列舉,如果在跳到長度為s2之前就出現不同點,那麼這個起點就不行,起點向右挪一位,重複這個操作直到跑到(s2-s1+1)的位置。
但這個演算法的複雜度非常高,最高可達到o(nm),顯然無法解決n>=1000的時候的情況,所以就有了kmp演算法。
首先看一看下面這個字串:
如果我們要在另乙個字串裡尋找這個字串是否出現過,假設我們現在按照暴力的做法去尋找出現了這種情況:
當匹配到acacd的時候,很明顯就咕咕了,這個時候按照暴力的思路會直接從cacd....開始找,但如果讓我們來進行下一步操作,我們會選擇從acdslf.....開始下一次匹配,因為我們很容易發現對於匹配失敗前的字串acac,字首ac與字尾ac是相同的!所以我們可以直接從第二個a的位置開始下一次匹配,就是這樣:
所以根據這個性質,我們可以減少一些無用的移動,從而降低複雜度。
kmp演算法步驟如下:
1.定義nxt陣列:nxt[i]表示對於匹配字串的[0~i]位,其相同字首和字尾的最大長度。還是以上面那張圖為例:
對於這個字串,nxt陣列儲存的分別就是"a","ac","aca","acac","acaca","acacac","acacacd","acacacde"的相同字首和字尾的最大長度,分別就是0(""),0(""),1("a"),2("ac"),3("aca"),4("acac"),0(""),0("")。
所以在匹配的時候,如果在s2第i位匹配失敗,那麼下一次就可以從當前位置pos+nxt[i]的地方開始匹配。
2.考慮匹配時如何找到當前點對應的最長匹配長度。
如果我們知道了前乙個位置的nxt值,那麼我們如何得到當前位置的nxt呢?用上面那個例子:
如果我們現在知道了第二個a的最長匹配為3,現在要求第二個c。
發現當前位置與匹配串的3+1位相同,c的最長匹配就為3+1=4。
然後匹配d,發現與4+1位匹配失敗,怎麼辦?
直接跳nxt啦~
為什麼呢?
因為acacd和acaca前四位是相同的,所以既然四位不行,那麼就看最長相同字首和字尾可不可以啦~
但是發現ac(acd)和(aca)ca並不匹配(看括號內的部分)。
所以再跳nxt!
然後就跳到0了。。。而且跳到0後d和a也不匹配,所以d這個位置最長匹配長度為0。
以此類推即可!
所以匹配部分就完了!
3.那麼問題來了,如何去求nxt陣列呢?
還是利用類似的思想,如果我們知道了i-1的nxt值,我們如何求i的nxt值呢?
首先,當前位置最佳情況的nxt值就是nxt[i-1]+1,所以先copy下nxt[i-1]。
如上,如果我們已經求得acaca的nxt為3,如何求acacac呢?
發現當前位置=s[nxt[i-1]+1],所以當前位置的nxt直接求得為nxt[i-1]+1。
然後求acacacd的nxt。
發現d與s[nxt[i-1]+1]=a不相等,所以跳nxt[i-1]的nxt。
相信很多人會一臉懵逼,為什麼?(反正之前我是打死沒看懂然後突然天空一聲巨響思路一下豁然貫通)
首先再看一下nxt陣列的定義:最長相同字首和字尾的長度。所以我們要在當前位置前加上那麼一段長度為x的字元,使s[1~x+1](當然會因為題目實際情況改一下下標,這裡為了方便就用1作為起始下標)與這段字元相同,當然我們希望越長越好,所以我們會從前一位的nxt再跳nxt,因為加的一段字元既是前面字串的字首也為其字尾,所以最大的即為前一位的nxt,第二小的即為前一位的nxt的nxt啦,這樣一直判一直判就可以得到最大的長度了。
好吧可能寫的有點模糊如果不懂歡迎提問,我會解答!
然後貼**,例題洛谷模板
#includeusing namespace std;
const int maxn=1e6+10;
char s1[maxn],s2[maxn];
int len1,len2;
int tot;
int nxt[maxn];
void calc_nxt()
if(s2[k+1]==s2[q])
k++;
nxt[q]=k; }}
void kmp()
}int main()
一點關於KMP演算法的思考
演算法用途 匹配字串。給定乙個模式串 pattern string ababc 乙個待匹配串 abababc 最樸素的方法就是兩層迴圈,從左到右依次比較,時間複雜度為o m n kmp演算法 給定乙個模式串 pattern string ababababc 觀察模式串 如果有乙個待匹配串是am,第2...
KMP演算法的一點心得
kmp演算法最重要的就是得到 next 陣列,以 next j k 為例,在kmp演算法裡next陣列的意思是下標為 j 的字元失配時模式串要後移到k的位置重新開始比較,在求 next 陣列的過程中,我們也可以理解為是前 j 個字元中字首和字尾的相等的最大長度。void get next strin...
KMP的一點理解
假設現在我們面臨這樣乙個問題 有乙個文字串s,和乙個模式串p,現在要查詢p在s中的位置,怎麼查詢呢?我們可以利用雙指標的方式進行匹配但這時乙個非常消耗時間的問題出來了,一旦失配應該怎麼匹配,這時今天的主角就要登場啦,我們可以設乙個陣列用於記錄在失配點之前有多少個點是可以直接繼續匹配的,比如說對 12...