DamerauโLevenshtein distance
์ด ํฌ์คํธ๋ ๋ฐฑ์ค 15484๋ฒ: ์ต์ํธ์ง2์ 2326๋ฒ: ์ต์ ํธ์ง ๋ฌธ์ 2์์ ์ฐ๋ ์๊ณ ๋ฆฌ์ฆ์ธ <DamerauโLevenshtein distance>์ ๋ํด ์๊ฐํ๋ ํฌ์คํธ์ ๋๋ค. ์ง์ ์ ์ธ์ ๋ ํ์์ ๋๋ค :)
DamerauโLevenshtein distance
<ํธ์ง ๊ฑฐ๋ฆฌ; edit distance>๋ ๋ํ์ ์ธ DP ๋ฌธ์ ์ด๋ค. ๋ฐฑ์ค์์๋ 15483๋ฒ: ์ต์ํธ์ง ๋ฌธ์ ๋ฅผ ํตํด <edit distance>์ ๋ํ ๋ฌธ์ ๋ฅผ ํ ์ ์๋ค.
๋จผ์ <edit distance>์ ์ํฉ์ ์ดํด๋ณด๋ฉด, ๋ String s1
, s2
์ ๋ํด
- ์ฝ์ (Insertion)
- ์ญ์ (Deletion)
- ๊ต์ฒด(Replacement)
์ธ ๊ฐ์ง ์ฐ์ฐ์ ํตํด ๋ ๋ฌธ์๋ฅผ ๊ฐ๊ฒ ๋ง๋ค ์ ์๋ ์ต์ ํ์๋ฅผ ๊ณ์ฐํ๋ค.
๊ทธ๋ฐ๋ฐ, ์ต์ํธ์ง ๋ฌธ์ ์ ๋ค์ ๋ฌธ์ ์ธ ์ต์ํธ์ง2์์๋ ํ๋์ ์ฐ์ฐ์ด ๋ ์ถ๊ฐ๋๋ค.
4. ๊ตํ(Transposition with adjacent character): ๋ ์ธ์ ํ ๊ธ์์ ์์น๋ฅผ ์๋ก ๋ฐ๊ฟ ์ ์๋ค.
๋ฌธ์ ๋ฅผ ๋ณด๊ณ , ์ฒ์์๋ ๊ฝค ํ ๋ง ํ๋ค๊ณ ์๊ฐํด์ ๋จ์ํ โ๊ตํํ์ ๋ matching cost๊ฐ 0์ด ๋๊ณ , ๋ ๊ทธ๋์ DP ๊ฐ์ด ์๋ค๋ฉด, Transpotion!โ์ธ ์์ผ๋ก 4๋ฒ์งธ ์ฐ์ฐ์ ์ฒ๋ฆฌํด๋ดค๋๋ฐ, WA๋ฅผ ๋ฐ์์๋ค.
๊ฒ์ํด๋ณด๋, โTranspotionโ ์ฐ์ฐ์ ์์ ๊ฒฝ์ฐ๋์ ๋ค๋ฅด๊ฒ ์ฝ๊ฒ ๊ณ์ฐ๋์ง ์๊ณ , <DamerauโLevenshtein distance>1๋ฅผ ํตํด ๊ตฌํด์ผ ํ๋ค.
<DL-distance>๋ ์คํ ์์ (misspell correction)์์ ํ์ฉํ๋ ์๊ณ ๋ฆฌ์ฆ์ด๋ค. DL-distance์์ ์ฐ๋ 4๊ฐ์ง ๊ฒฝ์ฐ๋ ์ฐ๋ฆฌ๊ฐ ํํ ํ๋ ์คํ์ ๊ฒฝ์ฐ๋ค์ด๋ฉฐ, ๊ตฌ๊ธ ๊ฒ์์์ ๊ฒ์์ ์๋ชป ์ ๋ ฅํด๋ ์ ์ ํ ์๋์ ํํ๋ก ๋ณํํด์ฃผ๋ ๊ฒ ์ญ์ ์ด๋ฐ DL-distance๋ก ์ ์ฌ๋๋ฅผ ํ๋จํ๊ธฐ ๋๋ฌธ์ด๋ค.
Algorithm
DL-distance๋ฅผ ๊ตฌํ๋ ์๊ณ ๋ฆฌ์ฆ์๋ <OSA distance; Optimal String Alignment distance>์ <DL-distance with adjacent transposition>, ๋ ๊ฐ์ง ์๊ณ ๋ฆฌ์ฆ์ด ์๋ค. ์ด๋, ํ์๋ฅผ true DL-distance๋ผ๊ณ ์ฌ๊ธด๋ค.
OSA์ DL ๋ชจ๋ transposition correction์ ์ง์ํ๋ค. ๊ทธ๋ฌ๋ <OSA distanace>์ ๊ฒฝ์ฐ โno substring is edited more than onceโ๋ผ๋ ์ก์ฝ์ด ์๋ค. ๋ณธ์ธ์ ๋์ถฉ โtranspositionํ substring ์ฌ์ด์ insertion์ ํฌํจํ ๋ค๋ฅธ ์ฐ์ฐ์ ์ํํ ์ ์๋คโ๋ผ๊ณ ์ ์ฝ์ ์ดํดํ๋ค.
์ด ์ ์ฝ์ด ์ critical ํ์ง๋ Wikipedia์ ์ ์๋๋ ์์๋ฅผ ํตํด ์ดํดํ ์ ์๋ค.
OSA ์๊ณ ๋ฆฌ์ฆ์ ๊ตฌํํ๊ธฐ๋ ์ฝ๊ณ , ๋ ๋ณธ์ธ์ด ์ฒ์ ์๋ํ ์ ๊ทผ์ผ ๋งํผ ์ง๊ด์ ์ด๊ธฐ ๋๋ฌธ์ ์ฌ๊ธฐ์ ๋ฐ๋ก ์ค๋ช ํ์ง๋ ์๊ฒ ๋ค ๐ ์ด๋ฒ ํฌ์คํธ์์๋ true DL-distance๋ง ํ๋ฒ ์ ๋๋ก ์ดํด๋ณด์!
Algorithmic Detail
์ด ๋ถ๋ถ์ โ๊ตฌ๋ฐํ๋ง ๊ตฌ๋ฐํ๋งโ๋์ ํฌ์คํธ์ ํฌ์คํธ๋ฅผ ๋ง์ด ์ฐธ๊ณ ํ๋ค. (๋จ, ๊ตฌ๋ฐํ๋ง ๋๊ณผ๋ ๋ค๋ฅด๊ฒ, Wikipedia์ ์ ์๋ DL-distance ์๊ณ ๋ฆฌ์ฆ์ ๊ทธ๋๋ก ์ดํดํ๊ณ ํด์ํด์ ๊ธฐ์ ํ์๋ค.)
๋จผ์ , ์ฝ์ , ์ญ์ , ๊ต์ฒด์ ๋ํ ๋ถ๋ถ์ ๊ธฐ์กด์ <edit distance>์ ๋์ผํ๋ค.
์ถ๊ฐ๋ transposition ์ฐ์ฐ์ ์๋์ ๊ฐ์ด ์ํ๋๋ค. s1 = "ca"
, s2="abc"
์ ์์๋ฅผ ํตํด ์ดํด๋ณด์.
๋จผ์ , ํ์ฌ i=2
, j=3
๋ผ๊ณ ํ์. ์ฆ, s1[i=2] = 'a'
, s2[j=3]='c'
์ธ ์ํฉ์ด๋ค.
์ด๋, s2
์์ j=3
๋ณด๋ค ์์ผ๋ฉด์, s1[i=2]='a'
์ ๊ฐ์ ๋ฌธ์๋ฅผ ๊ฐ๋ ๊ณณ์ ์์น๋ฅผ l
์ด๋ผ๊ณ ํ์! ๋ฐ๋๋ก s1
์์ i=2
๋ณด๋ค ์์ผ๋ฉด์, s2[j=3]='c'
์ ๊ฐ์ ๋ฌธ์๋ฅผ ๊ฐ๋ ๊ณณ์ ์์น๋ฅผ k
๋ผ๊ณ ํ์! ์์ ์์์์๋ l=0
, k=0
์ด๋ค.
์ด๋, transposition์ 3๋จ๊ณ๋ฅผ ํตํด ์ํ๋๋ค.
s1[k]
์s1[i]
์ฌ์ด๋ฅผ ์ ๋ถ ์์ ๊ณ (cost = i-k-1)s1[k]
์s1[i]
๋ฅผ ๊ตํํ๊ณ (cost = 1)s2[l]
๊ณผs2[j]
์ฌ์ด์ ์๋ ๋ชจ๋ ๋ฌธ์๋ฅผ ์ฝ์ (cost = j-l-1)
๋ฐ๋ผ์, transposition์ ๋น์ฉ์ ์ดํฉ (i-k-1) + 1 + (j-l-1)
์ด ๋๋ค!
์ด๊ฒ์ ์ฝ๋๋ก ํํํ๋ฉด,
dp[i][j] = min(insertion, deletion, replacement, dp[k][l] + (i-k-1) + 1 + (j-1-1))
์ด ๋๋ ๊ฒ์ด๋ค
์! ์ด์ ์ฝ๋ ๋ ๋ฒจ์์ ์ดํด๋ณด์. ์ฝ๋๋ Wikipedia์ pseudo-code๋ฅผ ์ดํดํ๊ณ ๊ทธ๋๋ก C++
๋ก ์ฎ๊ฒจ ์์ฑํ์๋ค. ์ฝ๋์์ k
, l
๋ฅผ ๊ณ์ฐํ๊ธฐ ์ํด da[]
, db
๋ฅผ ๋์
ํ๋ ํ
ํฌ๋์ ์ฌ์ฉํ๋ค๋ ์ ๋ ์ฃผ๋ชฉํ ๋ง ํ๋ค ๐คฉ
์ฌ๊ท ์์ด Button-Up ๋ฐฉ์์ผ๋ก ๊ตฌํํ๋ค.
#include <bits/stdc++.h>
#define MAX 1005
using namespace std;
int dp[MAX][MAX];
int da[26]; // s1์์ ํ์ฌ i๋ณด๋ค ์์ผ๋ฉด์, s2[j]์ ๊ฐ์ ๋ฌธ์๋ฅผ ๊ฐ๋ ๊ณณ์ ์์น; $k$
int Damerau_Levenshtein(string a, string b) {
// initialization
int maxDist = a.size() + b.size();
dp[0][0] = maxDist;
for (int i = 1; i <= a.size() + 1; i++) {
dp[i][0] = maxDist;
dp[i][1] = i - 1;
}
for (int j = 1; j <= b.size() + 1; j++) {
dp[0][j] = maxDist;
dp[1][j] = j - 1;
}
fill_n(da, 26, 1);
// DP process
for (int i = 2; i < a.size() + 2; i++) {
// db: s2์์ ํ์ฌ j๋ณด๋ค ์์ผ๋ฉด์, s1[i]์ ๊ฐ์ ๋ฌธ์๋ฅผ ๊ฐ๋ ๊ณณ์ ์์น; $l$
int db = 1;
for (int j = 2; j < b.size() + 2; j++) {
int k = da[b[j - 2] - 'a'];
int l = db;
int cost;
if (a[i - 2] == b[j - 2]) {
cost = 0;
db = j; // ํ์ฌ s[i]์ ๊ฐ์ ๊ณณ์ ์์น๋ฅผ db์ ๊ธฐ๋ก!
} else {
cost = 1;
}
dp[i][j] = min(dp[i - 1][j - 1] + cost,
min(dp[i][j - 1] + 1,
min(dp[i - 1][j] + 1,
dp[k - 1][l - 1] + (i - k - 1) + 1 + (j - l - 1))));
}
da[a[i - 2] - 'a'] = i;
}
return dp[a.size() + 1][b.size() + 1];
}
int main() {
string s1, s2;
cin >> s1;
cin >> s2;
cout << Damerau_Levenshtein(s1, s2);
return 0;
}
๋๋ฒ๊ทธ๋ฅผ ์ํด ์ถ๋ ฅํจ์๋ ๋ง๋ค์ด ๋๋ค.
void printDP(int N, int M) {
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
printf("%d ", dp[i][j]);
}
printf("\n");
}
printf("da: ");
for (int k = 0; k < 26; k++) {
printf("%d ", da[k]);
}
printf("\n");
printf("==========================\n");
}
!! 15484๋ฒ: ์ต์ํธ์ง2๋ฅผ ํด๊ฒฐํ๋ค!
์์ ์ฝ๋์์ ์ฝ๊ฐ๋ง ์์ ํ๋ฉด, 2326๋ฒ: ์ต์ ํธ์ง ๋ฌธ์ 2๋ ์ฝ๊ฒ AC๋ฅผ ๋ฐ์ ์ ์๋ค ใ ใ