최장 공통 부분 수열
최장 공통 부분 수열
개요
최장통 부분 수열(Longest Subsequence, 이하 LCS)은 개 이상의 문자열(또는 수열)에서 동시에 나타나는 부분 수열(subsequence) 중 가장 긴 것을 찾는 문제입니다. 이 알고리즘은 자연어처리(NLP), 생물정보학, 버전 관리 시스템(예: [git diff](/doc/%EA%B8%B0%EC%88%A0/%EC%86%8C%ED%94%84%ED%8A%B8%EC%9B%A8%EC%96%B4/%EB%B2%84%EC%A0%84%EA%B4%80%EB%A6%AC/git%20diff)
), 텍스트 비교 도구 등 다양한 분야에서 핵심적으로 활용됩니다.
부분 수열이란 원래 수열에서 일부 요소를 삭제하여 얻을 수 있는 새로운 수열을 의미하며, 요소의 순서는 유지되어야 하지만, 연속적일 필요는 없습니다. 예를 들어, 수열 ABCBDAB
의 부분 수열에는 ABD
, BCB
, ABBA
등이 포함될 수 있습니다.
LCS는 문자열 간의 유사도를 측정하는 데 유용하며, 특히 자연어처리에서는 문서 간 유사성 분석, 기계 번역 평가, 오타 수정, 문장 정렬 등에 응용됩니다.
알고리즘 원리
1. 문제 정의
두 수열 X = x₁, x₂, ..., xₘ
과 Y = y₁, y₂, ..., yₙ
이 주어졌을 때, X와 Y의 공통 부분 수열 중 길이가 가장 긴 것을 찾는 것이 목표입니다.
예:
- X = "AGCAT"
- Y = "GACAT"
- 가능한 공통 부분 수열: "ACAT"
, "GAT"
, "GCAT"
등
- 최장 공통 부분 수열: "GAT"
또는 "ACAT"
(길이 4)
2. 동적 프로그래밍 접근
LCS 문제는 동적 프로그래밍(Dynamic Programming, DP)을 통해 효율적으로 해결할 수 있습니다. 이 방법은 중복된 하위 문제를 저장하고 재사용함으로써 시간 복잡도를 줄입니다.
점화식 (Recurrence Relation)
L[i][j]
를 X
의 첫 i
개 문자와 Y
의 첫 j
개 문자의 LCS 길이라고 정의합니다.
L[0][j] = 0
(X가 빈 문자열)L[i][0] = 0
(Y가 빈 문자열)- 만약
X[i-1] == Y[j-1]
, 즉 마지막 문자가 같으면: L[i][j] = L[i-1][j-1] + 1
- 그렇지 않으면:
L[i][j] = max(L[i-1][j], L[i][j-1])
이 점화식을 바탕으로 m×n
크기의 2차원 테이블을 채워 나갑니다.
예시 계산
X = "ABCD"
, Y = "ACBD"
Ø | A | C | B | D | |
---|---|---|---|---|---|
Ø | 0 | 0 | 0 | 0 | 0 |
A | 0 | 1 | 1 | 1 | 1 |
B | 0 | 1 | 1 | 2 | 2 |
C | 0 | 1 | 2 | 2 | 2 |
D | 0 | 1 | 2 | 2 | 3 |
최종 값 L[4][4] = 3
이며, 실제 LCS는 "ABD"
또는 "ACD"
입니다.
알고리즘 구현
다음은 Python을 사용한 LCS 길이 계산 및 실제 수열 복원 예시입니다:
def lcs_length_and_sequence(X, Y):
m, n = len(X), len(Y)
# DP 테이블 초기화
dp = [[0] * (n + 1) for _ in range(m + 1)]
# 테이블 채우기
for i in range(1, m + 1):
for j in range(1, n + 1):
if X[i-1] == Y[j-1]:
dp[i][j] = dp[i-1][j-1] + 1
else:
dp[i][j] = max(dp[i-1][j], dp[i][j-1])
# LCS 수열 복원
lcs = []
i, j = m, n
while i > 0 and j > 0:
if X[i-1] == Y[j-1]:
lcs.append(X[i-1])
i -= 1
j -= 1
elif dp[i-1][j] > dp[i][j-1]:
i -= 1
else:
j -= 1
return dp[m][n], ''.join(reversed(lcs))
# 사용 예
X = "AGCAT"
Y = "GACAT"
length, sequence = lcs_length_and_sequence(X, Y)
print(f"LCS 길이: {length}, 수열: {sequence}") # 출력: LCS 길이: 4, 수열: ACAT
시간 및 공간 복잡도
항목 | 값 |
---|---|
시간 복잡도 | O(m × n) |
공간 복잡도 | O(m × n) |
단, 공간 최적화를 위해 두 줄만 유지하는 방식으로 공간 복잡도를 O(min(m, n))
로 줄일 수 있습니다. 다만 이 경우 실제 수열 복원은 불가능하거나 추가 처리가 필요합니다.
응용 분야
1. 자연어처리 (NLP)
- 문서 유사도 측정: 두 문장 또는 문서의 LCS를 통해 구조적 유사성을 분석합니다.
- 오타 감지 및 수정: 입력 문장과 정답 문장을 비교해 차이를 식별합니다.
- 기계 번역 평가: 예측 문장과 참조 문장의 LCS를 기반으로 정확도를 계산합니다.
2. 버전 제어 시스템
git diff
나diff
명령어는 LCS 알고리즘을 기반으로 파일 간 변경 사항을 비교합니다.- 추가/삭제된 부분을 추적하기 위해 LCS의 보완 알고리즘인 Myers diff 알고리즘이 사용됩니다.
3. 생물정보학
- DNA 또는 단백질 서열 정렬에 활용됩니다.
- 유사한 유전자 서열을 찾는 데 중요한 기초 기술입니다.
관련 알고리즘 및 확장
- 최장 공통 부분 문자열(Longest Common Substring): 부분 수열이 아닌 연속된 부분 문자열을 찾는 문제입니다. DP 접근법이 유사하지만 조건이 다릅니다.
- 편집 거리(Edit Distance): 삽입, 삭제, 치환을 통해 한 문자열을 다른 문자열로 변환하는 최소 연산 횟수. LCS와 밀접한 관련이 있으며,
편집 거리 = m + n - 2 × LCS
로 근사 가능합니다. - Hirschberg’s 알고리즘: 공간 복잡도
O(min(m, n))
를 유지하면서 실제 LCS 수열을 복원할 수 있는 분할 정복 기반 알고리즘입니다.
참고 자료
- Cormen, T. H., Leiserson, C. E., Rivest, R. L., & Stein, C. (209). Introduction to Algorithms (3rd ed.). MIT Press.
- Gusfield, D. (1997). Algorithms on Strings, Trees, and Sequences: Computer Science and Computational Biology. Cambridge University Press.
- Myers, E. W. (1986). "An O(ND) Difference Algorithm and Its Variations". Algorithmica.
관련 문서
LCS는 단순해 보이지만, 실세계 응용에서 중요한 기초 알고리즘으로, 자연어처리 기술의 정교한 분석을 가능하게 합니다.
이 문서는 AI 모델(qwen-3-235b-a22b-instruct-2507)에 의해 생성된 콘텐츠입니다.
주의사항: AI가 생성한 내용은 부정확하거나 편향된 정보를 포함할 수 있습니다. 중요한 결정을 내리기 전에 반드시 신뢰할 수 있는 출처를 통해 정보를 확인하시기 바랍니다.