初めて関数型言語を学習したので、向いてそうな動的計画法のアルゴリズムを書いてみました。
凝った事をしているわけではないのですが、名前が必殺技みたいでカッコイイですね。
levenshtein.hs
levenshtein :: String -> String -> Int
levenshtein str1 str2 = d !! wl1 !! wl2
where
wl1 = length str1
wl2 = length str2
d = [[distance m n | n<-[0..wl2]] | m<-[0..wl1]]
distance i j
| i == 0 = i
| j == 0 = j
| otherwise = minimum [ d!!(i-1)!!j + 1
, d!!i!!(j-1) + 1
, d!!(i-1)!!(j-1) + cost]
where
cost = if str1 !! (i-1) == str2 !! (j-1) then 0 else 1
こんな感じでレーベンシュタイン距離が計算されます。
*Main> levenshtein "abracadabra" "ababababa"
4
アルゴリズム
レーベンシュタイン距離を算出するための、動的計画法のアルゴリズムそのものは、wikipediaと下記を参考にさせて頂きました。
naoyaのはてなダイアリー | 編集距離 (Levenshtein Distance)
一応超ざっくり説明すると、下記のようなマトリクスを用意して、
i/j | - | a | p | p | l | e |
---|---|---|---|---|---|---|
- | 0 | 1 | 2 | 3 | 4 | 5 |
p | 1 | |||||
l | 2 | |||||
a | 3 | |||||
y | 4 |
[i,j]は下記①、②、③の内の最も小さい数
①[i, j-1] + 1
②[i-1, j] + 1
③もし文字列1[i] = 文字列2[j] なら[i-1, j-1], そうでないなら[i-1, j-1] + 1
という漸化式で求まります。
i/j | - | a | p | p | l | e |
---|---|---|---|---|---|---|
- | 0 | 1 | 2 | 3 | 4 | 5 |
p | 1 | 1 | 1 | 2 | 3 | 4 |
l | 2 | 2 | 2 | 2 | 2 | 3 |
a | 3 | 2 | 3 | 3 | 3 | 3 |
y | 4 | 4 | 3 | 4 | 4 | 4 |