KMP字符串匹配

這裏寫圖片描述

    我們假設有上圖字符串S:abcaab和T:abcababcaabab字符匹配需求,左邊是樸素算法:即從T的第0位和分別和S的1~n位開始比較,相同則用黃色標註,不同則用紅色標註,如果遇到不同,然後T的第0位和下一位開始重新來過開始第二輪比較。但是,在這個比較的過程中,我們會發現兩種情況:
    1.   0~3位分別相同,即T[0]=S[0],T[1]=S[1],T[2]=S[2],T[3]=S[3],同時T[0]!=T[1]!=T[2],所以顯然T[0]!=S[1]!=S[2],所以顯然T[0]和S[1],S[2]的比較是沒有必要的,所以對於KMP來說,第二輪和第三輪的比較的次數是都是0!
    2.   然後,我們再看第四輪比較,我們同時發現,由於abca,前一位和後一位是相同的,所以當開始第三輪的時候,T[0]=S[3],這次比較也是多餘的,直接比較T[1]?=S[4],發現相等,T[2]?=T[5],發現不等,跳到下一輪。

    這兩種情況所帶來的效果就是:本來遇到不匹配的位置T[j]!=S[i]時是應該“回溯”到T[0],用T[0]與上次和T[0]比較的S[n]下一位S[n+1]開始比較的,可是由於T串自身的一些特點,使得T不用“回溯”到T[0],而是“回溯”到T[j],然後繼續和S[i]比較,所以問題來了:這個位置j到底是如何規定的?

    “回溯”是KMP算法的的關鍵所在,求出回溯點j也就是找到了KMP的核心所在。

    當T[4]!=S[4]時,由於第一種情況,所以首先T[0]不必和S[2],S[3]相比,又由於第二種情況,所以不必回溯到T[0],而只需回溯到T[1]?=T[4]。所以第一種情況決定了S[i]不用回溯到S[n+1],第二種情況決定了T[j]不用回溯到T[0],而這個T[1]中的j=1,就是出現不匹配的時j位置之前,即T[0]~T[j-1]有多少相同的前後綴,例如我們假設是在T[5]的時候出現的不匹配T[5]!=S[5],則下一輪比較,只需比較T[2]?=T[5],這個2就是T[0]~T[4]之間有兩個前後綴相同!所以我們要做的就是對於T,求出每一個位置之前有多少相同的前後綴:

    首先:規定T[0]=-1,T[1]由於1位置之前只有一個元素,所以T[1]=0
    然後:每有一個後綴和前綴元素相同,假設此時後綴位置爲i,則T[i+1]回溯值爲此時回溯值加1,同時開始比較i+1和j+1,我們通常把next[i]稱爲回溯的位置值。實際上此時n位前綴和n位後綴也處於上述S和T的比較過程中,例如對於ababaaaba:
這裏寫圖片描述
    在T[5]時,因爲T[0~2]=T[2~4],求出next[5]=3時,接下來要求next[6],即比較(T[3]=b) ?= (T[5]=a),此時顯然不同!那我們接下來要做什麼邏輯呢來判斷next[6]呢?
這裏寫圖片描述

    此時,next[5]的求解處於上圖中的位置,由文章起始講的“回溯”可知,接下來要比較的是T[j=1]?=T[j=5],發現不等,則比較T[j=0]?=T[j=5],然後相等,則認爲next[6]=j+1=1,然後依次類推求解接下來的值!在這個過程中j=3—>j=1—>j=0,也是回溯的問題,而此時回溯點已經在之前求出來了!

    說了這麼久,我們來看看實際的代碼是怎樣的!
    對於next值:

這裏寫圖片描述
    對於匹配函數:
這裏寫圖片描述

發佈了50 篇原創文章 · 獲贊 150 · 訪問量 14萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章