MIT 6.006 Introduction to Algorithms 9.2

9. Table Doubling, Karp-Rabin

Kuan-Yu Chen
2 min readMar 4, 2017

前提

前面提到在 Hashing 的幫忙下,可以達到

Insert / Delete / Search Time Cost = O ( 1 )

Hashing 的好處不只有這些!

還有更多的應用領域,比如這次會介紹 Text Search Engine ,也是利用到 Hashing 的幫忙。

結論

這次介紹如何利用 Rolling Hashing 的優點,把複雜的比對變得簡單:

  • Text Matching
  • File Matching

Hashing 好棒棒

字串比對問題

給予兩個 String s & t,請問 s 字串是否出現在 t 字串裡面:

s = "algorithm"
t = "/(wholeInboxText)"

t 是一個超乎想像的大型的字串,可能是你所有的email,也可能是全世界的website…

我們先從簡單的 algorithm 開始…

Simple Algorithm For Matching

for i in range( length(t) - length(s) ) {    if ( s == t[i -> i + length(s)] ){
return true
}
}
return false
Matching Algorithm

對 String t 跑一個 for loop,並且每次 i 都檢查 t 區間的每個字母是否等於 String s。這樣子的 algorithm 實在非常慢:

Time Cost = O( |s| * ( |t| - |s| ) ) = O( |s| * |t| )

尤其當你的 t 字串很大時。 s 很大時,你每次一個字一個字比對的成本也很高…

該如何解決?…Hashing!

將每次比對的大字串 hash 成容易比較的數字,讓每次比較的成本降低!

在這裡,我們需要的是一種特別的 Hashing:

Rolling Hash ADT

  • r = hash value of String x
  • r.append( c ) = hash( x + new char c )
  • r.skip() = hash( x remove first char )

Rolling Hash 有一個特性,你可以隨意地對 Hash 後的結果變動,變動後一樣保持 Hash 的結果:

//對字串 x 做 rolling hash
String x = "abc"
rollHash(x) = "123"
//對 x 增加字母 "d"
String x' = "abcd"
//重新hash的結果與執行append的結果一樣
rollHash(x') = "1234"
rollHash(x).append(d) = "1234"
//對 x 刪去第一個字母 "a"
String x'' = "bcd"
//重新hash的結果與執行skip的結果一樣
rollHash(x'') = "234"
rollHash(x').skip() = "234"

我們可以利用 Rolling Hash Method 的特色,重新設計剛剛的matching algorithm:

Karp — Rabin Algorithm

var rs = rollingHash(s)
var rt = rollingHash(t[0 -> length(s)])
for i in range( length(t) - length(s) ) {
rt.skip()
rt.append(t[i])
if ( rs == rt ){
//進一步檢查hash前的值是否相同
if (s == t[i -> i + length(s)]) {
return true
}
}
}
return false

對 String t 跑一個 for loop,並且每次 i 都檢查 Hash 後的結果,如果結果match,才真的一個字一個字的去比對:

Time Cost = O( |s| + |t| + #number of hash match * |s|)

這比原先的 algorithm 快得多了!

Rolling Hash

其實上週介紹的 Division Hash Method 就擁有 Rolling Hash 的特性,影片有去證明 Division Hash 擁有這樣的特性。

Division Method

hash(k) = k mod m

直接將 k 這個巨大的數字,模除 m (Number of Keys In Dictionary)後,作為新的 key

如果忘記了可以點下面連結:

下一堂課,我們會介紹另一種解決 collision 的辦法...

--

--