【算法】字符串匹配1 BF算法 RK算法

字符串匹配有多種方法,這裏先講最簡單的兩種算法: BF算法RK算法,複雜度也相對較高。
它們均爲單模式串匹配的算法,也就是一個串跟一個串進行匹配。

BF算法

簡介

Brute Force,暴力匹配算法,也叫樸素匹配算法。
比較簡單、好懂,但相應的性能也不高。

在字符串 A 中查找字符串 B ,那字符串 A 就是主串,字符串 B 就是模式串
主串的長度記作 n ,模式串的長度記作 m ,所以n>m 。

算法思想

在主串中,檢查起始位置分別是 0 、1、 2…n-m 且長度爲 m 的 n-m+1 個子串,看有沒有跟模式串匹配的。

BF

時間複雜度

極端情況下,要比較 n-m+1 次,每次需要比對 m 個字符。所以最壞情況時間複雜度O(n*m)

常用原因

雖然複雜度高,但實際開發中很常用,原因如下:

  • 大部分情況下,模式串和主串的長度都不會太長。每次模式串與主串中的子串匹配時,當中途遇到不能匹配的字符的時候,就可以就停止了,不需要把 m 個字符都比對;
  • 算法思想簡單,代碼實現簡單。簡單意味着不容易出錯,如果有 bug 也容易暴露和修復。

RK算法

Rabin-Karp,由兩位發明者名字而來。可以看做是BF的升級版。

算法思想

通過哈希算法對主串中的 n-m+1 個子串分別求哈希值,然後逐個與模式串的哈希值比較大小。
如果某子串哈希值與模式串相等,那就說明對應子串和模式串匹配(先不考慮衝突)。
哈希值是一個數字,數字之間比較是否相等是非常快速。

RK

提高哈希計算效率

哈希算法計算子串的哈希值時,仍需要遍歷子串中的每個字符,需要改進。

改進方法: 要匹配的字符串的字符集中只包含 K 個字符,可以用一個 K 進制數來表示一個子串,這個 K 進制數轉化成十進制數,作爲子串的哈希值。

舉例解釋上述方法。

假如處理的字符串只包含 a-z 這26 個小寫字母,那用二十六進制來表示一個字符串。
我們把26 個字符映射到 0~25 這 26 個數字。

再把二十六進制數轉化成十進制數,進位從 10 改成 26 就可以。
在這裏插入圖片描述
這種計算方法,在主串中相鄰兩個子串的哈希值的計算公式有一定關係。
在這裏插入圖片描述

規律:相鄰兩個子串 s[i-1] 和 s[i] ( i 表示子串在主串中的起始位置,子串的長度都爲 m ),對應的哈希值計算公式有交集。
公式表示如下:
在這裏插入圖片描述
事先計算好 26026^026126^126226^2……26m126^{m-1} ,存儲在長度爲 mm 的數組中,公式中的 “ 次方 ” 就對應數組的下標。
在這裏插入圖片描述

時間複雜度

第一部分:通過設計特殊的哈希算法,只需掃描一遍主串就能計算出所有子串的哈希值,所以時間複雜度是 O(n) 。
第二部分:需要比較 n-m+1 個子串的哈希值,比較的複雜度是O(1),總的複雜度也是 O(n)。

所以,RK 算法整體的時間複雜度就是O(n)

解決衝突問題

上面的哈希算法沒有衝突,但是指數計算可能導致哈希值結果非常大,超出計算機表示範圍。
解決方法就是允許衝突,從而減小計算範圍。

允許衝突的哈希算法很多,舉一個例子。

將每一個字母從小到大對應一個素數,把字符串中每個字母對應的數字相加,得到的和作爲哈希值。

怎麼解決衝突呢?其實很簡單。
比較完哈希值後,
不相等的話,則無須比較,肯定不匹配;
相等的話,把兩個字符串本身再比較一次即可。

這種方法前提是要控制衝突概率,達到可以接受的狀態,否則算法會退化的厲害,變成 O(n*m) 。

本文是極客時間王爭 數據結構與算法 課程的筆記,推薦此課,喜歡可以購買課程。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章