에듀테크 프로젝트 대시보드
편집 거리 (Levenshtein)
휴대폰에 recieve라고 치면 receive로 고쳐 주고,
Git이 git stauts 대신 status를 제안하는 이유는 무엇일까?
컴퓨터는 두 단어가 "얼마나 비슷한지"를 편집 거리라는 숫자로 잰다.
편집 거리는 글자 하나 삽입 / 글자 하나 삭제 / 글자 하나 교체 세 가지 연산만 써서
단어 A를 단어 B로 만들 때 필요한 최소 연산 횟수다.
예를 들어 kitten → sitting 은 3 (k→s 교체, e→i 교체, 끝에 g 삽입).
칸 D[i][j] = "A의 앞 i글자"를 "B의 앞 j글자"로 바꾸는 최소 편집 거리.
각 칸은 왼쪽·위·왼쪽위 세 이웃에서만 계산된다.
표를 왼쪽 위에서 오른쪽 아래로 한 칸씩 채우면, 이미 계산해 둔 이웃 값만 재활용하므로
각 칸은 O(1)에 정해진다. 표 크기가 (m+1) × (n+1) 이므로
전체 시간·공간은 O(m·n). 완성된 표의 오른쪽 아래 칸이 답이고,
거기서 "어느 이웃을 골랐는지" 거꾸로 따라가면 실제 연산 순서(정렬)를 복원할 수 있다.
| 연산 | 표에서의 이동 | 예시 |
|---|---|---|
| 교체(substitute) | 대각선 ↖ (글자 다르면 +1) | cat → cut |
| 일치(match) | 대각선 ↖ (글자 같으면 +0) | cat → cat |
| 삽입(insert) | 왼쪽 ← (B의 글자 추가, +1) | cat → cart |
| 삭제(delete) | 위 ↑ (A의 글자 제거, +1) | cart → cat |
# O(m*n) 시간, O(n) 공간 (한 줄만 유지) def edit_distance(a, b): m, n = len(a), len(b) prev = list(range(n + 1)) # D[0][j] = j for i in range(1, m + 1): cur = [i] + [0] * n # D[i][0] = i for j in range(1, n + 1): cost = 0 if a[i-1] == b[j-1] else 1 cur[j] = min( prev[j] + 1, # 삭제 cur[j-1] + 1, # 삽입 prev[j-1] + cost, # 교체/일치 ) prev = cur return prev[n] print(edit_distance("kitten", "sitting")) # 3
※ 위 데모는 전체 표를 저장해 역추적(정렬)까지 보여주므로 O(m·n) 공간을 쓴다. 거리 값만 필요하면 코드처럼 두 줄만 있으면 된다.