關於字符串匹配算法有不少,以前我有講過一篇 KMP 匹配算法:圖解字符串匹配 KMP 算法,不懂 kmp 的建議看下,寫的還不錯,這個算法雖然很牛逼,但在實際中用的並非特別多。至於選擇哪種字符串匹配算法,在不一樣的場景有不一樣的選擇。算法
在咱們平時文檔裏的字符查找裏安全
採用的就是 Boyer-Moore 匹配算法了,簡稱BM算法。這個算法也是有必定的難度,不過今天,我選用一個例子,帶你們讀懂這個字符串匹配 BM 算法,看完這篇文章,保證你可以掌握這個算法的思想。數據結構
首先我先給出一個字符串和一個模式串工具
接下來咱們要在字符串中查找有沒有和模式串匹配的字串,步驟以下:開發工具
一、
和其餘的匹配算法不一樣,BM 匹配算法,是從模式串的尾部開始匹配的,因此咱們把字符串和模式串的尾部對齊。3d
顯然,從圖中咱們能夠發現,s 和 e 並不匹配。這時咱們把「s」 稱之爲壞字符,即表明不匹配的字符。並且咱們能夠發現,s 和模式串中的任意一個字符都不匹配,因此這時,咱們能夠直接把模式串移動到 s 的後面。視頻
二、blog
從圖中能夠看出,此時 p 和 e 不匹配,因此 p 是一個壞字符,不過,咱們能夠發現 「p」 包含在模式串中資源
因此,咱們不能像第一步那樣,把模式串直接所有移到 p 的後面去,而是移動兩位,讓兩個 p 對齊。開發
四、
那麼問題來了,當咱們碰到碰到壞字符的時候,該移動幾位呢?
下面我和你們講一下這個問題,首先咱們要算出模式串中兩個字符的下標。這兩個字符分別是
(1)模式串中與壞字符對應的那個字符的下標,在咱們上面那個例子中,就是 e。
顯然,這個 e 的下標是 6(從0開始算起)。咱們用變量 t1 來表明這個字符的下標吧。
(2)壞字符在模式串中的下標,在咱們上面那個例子中,壞字符在模式串中的下標爲 4,咱們用變量 t2 來表明這個下標,如圖
找出這兩個字符的下標以後,咱們就能夠計算移動的位數了
移動的位數 = t1 - t2。
例如上面的例子步驟 2 中 t1 = 6, t2 = 4,因此移動了 t1 - t2 = 2 位。
(1)這個時候可能有人會問了,那若是模式串中有多個 p 呢?
答是若是有多個,咱們只計算最右邊的那個(固然是移動的位數越少越安全了)
(2)可能又有人會問,那若是模式串中並不存在壞字符呢?例如步驟1
答是若是不存在的話,咱們把 t2 賦值爲 -1,即 t2 = -1。因此咱們步驟 1 中移動了 t1 - t2 = 6 - (-1) = 7 位。
好了,如今咱們已經解決了遇到壞字符以後,應該移動多少位的問題了。
咱們繼續匹配
五、
匹配,因此繼續匹配前面的字符
六、
匹配,繼續匹配前面的字符
七、
匹配,繼續匹配前面的字符
八、
匹配,繼續匹配前面的字符
九、
遇到壞字符 i,按照咱們前面的規則,能夠計算出 t1 = 2(就是a的下標)。t2 = -1(由於模式串不存在壞字符)。因此移動的位數是 t1 - t2 = 3。
可是,我想問一下,這是最好的移動方式嗎?有沒有更好的移動方法呢?接下來我就和你們介紹一種更好的方法,這種方法就是根據好後綴來移動位數。首先咱們先介紹下啥的好後綴。
在上面的例子中,咱們發現 "mple" 是可以成功匹配的
咱們把這些可以成功匹配的子串,稱之爲好後綴,因此呢,e,le,elp,mple 都是好後綴
由於 e, le, elp在以前的步驟中,也是可以成功匹配。不過 mple 是最長的好後綴。
接下來咱們要在模式串的前面尋找與好後綴匹配的子串,這句話的意思就是說,咱們要在模式串中尋找這樣一個子串s:s 與好後綴匹配,而且s中的字符不能與好後綴有重疊。
我舉個例子吧,例若有模式串 abcddab,而後好後綴分別是 b, ab, dab。那麼與好後綴匹配的字串有 b,ab。(由於abcddab前面中的b能夠與好後綴 b 匹配,前面的 ab 與好後綴 ab 匹配)。不過,沒有與好後綴 dab 匹配的子串。
那麼問題來了,若是咱們找到了多個這樣的子串的話,咱們要選擇哪個呢?例如上面咱們找到了兩個,分別是 a,ab。
這個時候,咱們選擇與比較長的那個好後綴匹配的子串,例如,上面的例子中,咱們會選擇 ab,咱們把這個被選中的子串(ab)稱之爲好前綴吧(我是爲了後面方便描述,纔給它這個一個稱呼)。
找出了好後綴和好前綴以後 ,咱們就能夠知道要移動幾位了,公式以下:
移動的位數 = 好後綴的下標 - 好前綴的下標。
固然,好後綴有多個,咱們是選擇和好前綴匹配的那一個。那麼好後綴的下標怎麼算呢?,計算方法是按照好後綴的最後一個字符的下標爲準,例如模式串 abcddab 中好後綴 ab 的下標爲 6(下標從 0 開始算起)。好前綴下標的方法也是同樣,以最後一個字符的下標位準,例如模式串 abcddab 中,好前綴 ab 的下標爲 1。
這裏可能有人會問,那若是不存在這樣的好前綴呢?若是不存在的話,就用 -1 充當好前綴的下標。
知道了移動位數以後,咱們繼續來匹配咱們上面的例子
十、
好後綴是 e, le, ple, mple,可是模式串中只有一個子串可以與好後綴 e 匹配,因此好前綴爲 e。
顯然,這個時候好前綴 e 的下標爲 0,好後綴 e 的下標爲 6,因此移動的位數爲 6。若是按照咱們最開始壞字符的移動規則的話,只能移動 3 位,而用好後綴能夠移動 6 位。
十一、
可能有人會問,兩個規則咱們應該要選擇哪個呢?
答案很簡單,把兩個規則的移動位數都算出來,選擇移動位數多的就是了。
這裏 p 是壞字符,而且不存在好後綴,因此採用壞字符的規則,移動 2 位。
十二、
這個時候,咱們能夠發現,模式串的字符所有都匹配了,這也意味着匹配結束了。
這篇文章我是採用直接舉例子的方式來說,我以爲這樣反而容易懂,而且在講的過程當中,可能沒有講的那麼全,這是由於我不想說的太全,由於把全部狀況都羅列處理的話,相信你容易暈。因此我才用這種方式,讓你先懂了這個 BM 的算法思想,以後的細節,你能夠再去琢磨。
爲了講清楚這個算法,也算是絞盡腦汁,特別是爲了可以以最簡單的方式來說解好後綴的規則,停筆思索了很久,最後也百度搜索了幾篇文章,看看別人都怎麼講,還翻開了我以前購買的數據結構與算法的專欄,,,最後結合本身的想法寫了出來。但願這篇文章,可以讓你讀懂給 BM 算法,這個算法的核心就是壞字符和好後綴了,相信你必定可以搞懂!後面會連續講解幾篇與樹有關的文章。
若是你以爲這篇內容對你挺有啓發,爲了讓更多的人看到這篇文章:不妨
一、點贊,讓更多的人也能看到這篇內容(收藏不點贊,都是耍流氓 -_-)
二、關注我和專欄,讓咱們成爲長期關係
三、關注公衆號「苦逼的碼農」,主要寫算法、計算機基礎之類的文章,裏面已有100多篇原創文章
大部分的數據結構與算法文章被各類公衆號轉載相信必定能讓你有所收穫
我也分享了不少視頻、書籍的資源,以及開發工具,歡迎各位的關注個人公衆號:苦逼的碼農,第一時間閱讀個人文章。