老大難的KMP

2021-10-09 22:36:43 字數 2484 閱讀 7818

此外,這篇博文寫的也是特別清楚,只是兩篇文章對於next陣列的定義有些許不同,感興趣的同學可以閱讀學習。位址

其實是三個人的名字縮寫,分別為knuth,morris和pratt。

kmp主要應用在字串匹配上,主要思想是**當出現字串不匹配時,可以知道一部分之前已經匹配的文字內容,可以利用這些資訊避免從頭再去做匹配了

例如,在乙個串中查詢是否出現過另乙個串,這是kmp的看家本領。

那麼如何記錄這些資訊呢???這是kmp的重點,也是next陣列所包含的意義!所以在接下來的學習和應用中,要深刻理解next陣列裡的數字表示的是什麼,為什麼這麼表示?**

next陣列其實就是乙個字首表,是用來回溯的。它記錄了模式串與主串(文字串)不匹配的時候,模式串應該從**開始重新匹配。

為了能清楚字首表的來歷,舉個例子:

要在文字串:aabaabaafa中查詢是否出現過乙個模式串:aabaaf

請記住文字串和模式串的作用,對於理解下文很重要,要不然容易看懵。

自行匹配發現,文字串中第六個字元b 和 模式串的第六個字元f,不匹配了。如果是一般的暴力匹配,發現不匹配,此時就要返回模式串的開頭,從頭匹配

但如果使用字首表,就不會從頭匹配,而是從上次已經匹配的內容開始匹配,找到了模式串中第三個字元b繼續開始匹配

這就是kmp相對於一般解法的優點。

所以,可以知道字首表的意義:當前位置匹配失敗時,字首表會告訴你下一步匹配中,模式串應該跳到哪個位置開始匹配,而不是像暴力解法一樣都從頭開始匹配。

所以,可以自己考慮一下,當第六個模式串匹配失敗時,應該跳到哪個位置重新開始匹配最高效???

想一想,是不是下面這句話總結的呢??

匹配失敗字元前有一段匹配成功的子模式串(也就是字串aabaa),它的最長相等的字首 和 字尾字串是子字串aa ,因為找到了最長相等的字首和字尾,匹配失敗的位置是字尾子串的後面,那麼我們是不是找到與其相同的字首的後面從新匹配就可以了??

所以字首表具有告訴我們當前位置匹配失敗,跳到之前已經匹配過的地方的能力。

以此類推:

長度為前4個字元的子串aaba,最長相同前字尾的長度為1。

長度為前5個字元的子串aabaa,最長相同前字尾的長度為2。

長度為前6個字元的子串aabaaf,最長相同前字尾的長度為0。

那麼把求得的最長相同前字尾的長度就是對應字首表的元素,如圖:

可以看出字首表裡的數值代表著就是:當前位置之前的子串有多大長度相同的字首字尾。

匹配時,找到的不匹配的位置, 那麼此時我們要看它的前乙個字元的字首表的數值是多少。

為什麼要看前乙個字元的字首表的數值呢,因為要找前面字串的最長相同的字首和字尾,所以要看前一位的 字首表的數值。

字首表有個問題不知道,大家發現了死迴圈沒。

看這個位置紅框的位置,如果要找下表1 所對應 字首表裡的數值的時候,字首表裡的數值依然是1,然後就要跳到下表1的位置,如此就形成了乙個死迴圈

如何怎麼避免呢,就把字首表裡的數值統一減一, 開始位置設定為-1 。 這一點對理解後面kmp**很重要!!

改為如圖所示:

這樣就避免的死迴圈,只不過後續取 字首表裡的數值的時候,要記得再+1,才是我們想要的值。

最後得到的新字首表在kmp演算法裡通常用乙個next陣列來表示。

注意這個next陣列就根據模式串求取的。

假設文字串長度為n,模式串長度為m;

因為在匹配的過程中,根據字首表不斷調整匹配的位置,可以看出匹配的過程是o(n),但之前還要單獨生成next陣列,時間複雜度是o(m)(next陣列的實現**將在後續文章中繼續講解),所以整個kmp演算法的時間複雜度是o(n+m)的。

所以,kmp很難嗎?

//自動獲取next陣列呢

void

getnext

(int

* next,

const string& s)

if(s[i]

== s[j +1]

) next[i]

= j;

// 將j(字首的長度)賦給next[i]

}}

解決Actions Pane排版的老大難問題

微軟在smart document技術中第一次引入了task pane這個自定義的可能。但是由於smart document需要xml expansion pack,所以部署會比較麻煩一點。而且smart document是基於com技術的,並且其上也只能放一些標準的控制項,所以使用的人也許並不多。...

什麼是程式設計師程式設計中的老大難問題?

許多程式設計師認為程式設計時,如何命名不僅是他們面臨的老大難問題,也是最重要的事情之一。上週,我發起了乙個 程式設計師程式設計中的老大難問題 的投票,主要是基於最近quora上的跟帖討論。根據大家的反響和投票結果,有一項投票遙遙領先,穩居第一 對於軟體開發人員來說,最大的難題是 如何命名 例如 給變...

什麼是程式設計師程式設計中的老大難問題?

許多程式設計師認為程式設計時,如何命名不僅是他們面臨的老大難問題,也是最重要的事情之一。上週,我發起了乙個 程式設計師程式設計中的老大難問題 的投票,主要是基於最近quora上的跟帖討論。根據大家的反響和投票結果,有一項投票遙遙領先,穩居第一 對於軟體開發人員來說,最大的難題是 如何命名 例如 給變...