kmp演算法主要解決的問題就是在字串(主串)中的模式(pattern)定位問題。記主串為t,模式串為p,則kmp演算法就是返回p在t**現的具體位置,如果沒有出現則返回-1。
如果 i 指標指向的字元和 j 指標指向的字元不一致,那麼把 i 右移1位,j 從0位開始,從新開始匹配:
如果 i 指標指向的字元和 j 指標指向的字元一致,則 i 與 j 都向後移動
基於以上想法得到了以下程式:
/*
暴力破解法
ts 主串
ps 模式串
如果找到,返回在主串中第乙個字元出現的下標,否則為-1
*/class
solution
else}if
(j == p.
length()
)else}}
;
暴力法能夠解決模式串匹配的問題,但不夠好。主要的問題在於匹配失敗之後我們對主串進行了回退(即:i = i - j + 1)。以下圖為例:
此時 c 與 b 不匹配,如果按照暴力破解的方法,我們會把i置於第1位,但如果我們要保持 i 不回退,我們應該怎麼做。kmp演算法的思路是:「利用已經部分匹配這個有效資訊,保持i指標不回溯,通過修改j指標,讓模式串盡量地移動到有效的位置。」
在這通過觀察可知合理做法是把j移動到2位。為什麼?
直觀的說是因為前面存在 a b 相同。而根本的原因在與:由於不匹配的是 c 與 b,這說明在這之前p串與t串是匹配的(均為:a b c a b),而對於 a b c a b 這一部分存在著字首(a b)與字尾(a b)相等,因此在t串與p串中存在著相同的字首與字尾。故p串的字首與t串的字尾相同,所以我們將j的位置調整至相等字首的後一位。
用數學表達就是:
當:t[i] != p[i] 時,有t = p
同時如有p = p
必有:t = p
結合下面理解:
上述的存在相等的字首與字尾解釋了:調整 j 的位置後 i ,j 之前字串仍然匹配的原因,下面介紹不修改 i 位置的正確性。以下圖為例:
首先,不修改 i 的位置相當於去除了以 i = 1 (i - j+1) ~4 (i - 1) 為起始位置的所有情況,那麼證明不修改 i 位置的正確性可以等價與證明從以(i - j+1)~(i - 1)開頭不存在可能解。可能解即p串與t串匹配。對模式串p的分析,如果存在某一字首與字尾相同則必然從t中字尾開始處匹配p的字首才能一直匹配至原不匹配處。
從上述的分析可知想讓 i 不後退,需要知道 j 調整到位置,而 j 調整的位置取決於p 中最長字首與字尾相等的位置,如有p = p,那麼 j 就調整到 k 位。我們用陣列儲存這一跳轉資訊,稱之為next陣列。
next陣列定義為:匹配模式串j位置失配,j應調整到的新位置。根據 j 的調整方法與模式串前 j-1 位最長前字尾相等的關係,可知next[j]的值應為模式串前 j - 1 位最長前字尾相等的字首末尾下一位。
下面給出next陣列求法和解釋:
class
solution
else
}return next;}}
;
初始化:當 j 為0時,如果這時候不匹配,怎麼辦?
j已經不能再左移了,也就是i在這一位已經不可能與模式串匹配了,這時候說明 i 可以直接右移一位。為了與p[j] =t[i]情況一起處理(i++,j++),定義next[0] = -1,得 i 指向下一位,j 為0。
當 j 為1時,如果這時候不匹配?
顯然,j指標一定後移到0的位置。
一般情況,由於我們的next陣列是按順序初始化的,假設我們現在在處理字首位k與字尾位i,求next[j + 1],如下圖所示:
因為比對到了 k 與 j ,說明p 與 p匹配(next[j] = k)
如果p[k] == p[j],那麼p 與 p匹配,那麼next[j+1] = k + 1=next[j] + 1(因為next[j+1]表示在前j位中最長前字尾相等的字首末尾的下一位也就是k+1)。
如果p[k] != p[j],說明此時前j位的最長字首到不了第 k 位,為了求next[j+1],我們要繼續尋找p[?] = p[j],
圖示a1與a2是相等的前字尾,由於p[k] != p[j]所以我們繼續尋找前 j 位的最長前字尾。我們取出next[k]所在的位置,由next陣列的定義,b1與b2相等,而由a1與a2相等,故存在b3與b2相等=>b1與b3相等,那麼我們就可以繼續判斷p[j] 是否等於 p[next[k]],如果相等就可以得到next[j + 1],不等繼續遞迴,直到k=-1,執行i++,k++。
好了,有了next陣列之後我們就可以寫kmp演算法了:
class
solution
else
}return next;
}int
kmp(string t, string p)
else}if
(j == p.
length()
)else}}
;
最後引用wnjxyk大佬的模板:
build為構建next陣列,改進的地方為把所有匹配解存入容器中返回
具體講解可通過鏈結檢視
namespace kmp}
vector<
int>
match
(const string &pattern,
const string &text)
return res;}}
;
參考:
詳解kmp演算法
kmp演算法的next陣列詳解
如果next陣列分析還是不清晰可以看看參考裡唐小喵的next陣列詳解
演算法 Kmp演算法初見
上面的說法有些官方了,其實用最最簡單的話來說就是,給計算機乙個最快的方法從乙個名單中找到你的名字,這個時候我們用這個演算法就再合適不過了。我們一般如果要是寫乙個文字匹配的演算法的話,最最簡單的就是用迴圈去匹配了,這個應該是個只要學過程式設計的同志都應該了解的方法,如果想要在一堆字母中找到abc的話,...
演算法 kmp匹配演算法
執行結果 心得收穫 完整 計算next陣列 next陣列的目標是求得從開始到當前位置的字串相同最大前字尾長度為多少 該值的作用是在當前位置的字元匹配失敗時,匹配字串應該從那裡開始繼續匹配,而不用回到開頭 時間複雜的 o m void calnextarray const string str,int...
演算法 KMP演算法 解釋
1.詳解kmp演算法 2.大話資料結構 3,kmp演算法易懂版 kmp演算法由d.e.knuth j.h.morris和v.r.pratt發表的模式匹配演算法。kmp演算法要解決的問題就是在字串 也叫主串 中的模式 pattern 定位問題。例子 輸入 主串 s abeabx 子串 t abx 輸出...