728x90
https://www.acmicpc.net/problem/9252
문제
LCS(Longest Common Subsequence, 최장 공통 부분 수열) 문제는 두 수열이 주어졌을 때, 모두의 부분 수열이 되는 수열 중 가장 긴 것을 찾는 문제이다.
예를 들어, ACAYKP와 CAPCAK의 LCS는 ACAK가 된다.
입력
첫째 줄과 둘째 줄에 두 문자열이 주어진다. 문자열은 알파벳 대문자로만 이루어져 있으며, 최대 1000글자로 이루어져 있다.
출력
첫째 줄에 입력으로 주어진 두 문자열의 LCS의 길이를, 둘째 줄에 LCS를 출력한다.
LCS가 여러 가지인 경우에는 아무거나 출력하고, LCS의 길이가 0인 경우에는 둘째 줄을 출력하지 않는다.
최장 공통 부분 수열(Longest Common Subsequence) 문제이다.
이 문제에서는 두 문자열의 LCS의 길이뿐만 아니라, LCS 또한 출력해야 한다는 점이 포인트이다.
LCS의 길이 구하기
점화식에 따라 dp배열을 만들면 다음과 같다.
전체 시간 복잡도는 O(len(a)*len(b))이다.
- C A P C A K
- [0, 0, 0, 0, 0, 0, 0]
A [0, 0, 1, 1, 1, 1, 1]
C [0, 1, 1, 1, 2, 2, 2]
A [0, 1, 2, 2, 2, 3, 3]
Y [0, 1, 2, 2, 2, 3, 3]
K [0, 1, 2, 2, 2, 3, 4]
P [0, 1, 2, 3, 3, 3, 4]
LCS 구하기
- dp배열의 (len(a), len(b))의 위치부터 시작한다.
- 왼쪽과 위쪽 값 중 하나 이상의 위치만 현재값과 다르다면 같은 값을 가지는 쪽으로 계속해서 이동한다.
- 현위치의현 위치의 왼쪽과 위쪽의 값이 모두가 현재값과 다르다면 현 위치의 알파벳을 배열에 담고 좌측 위로 이동한다.
- 현재값이 0이 될 때까지 반복한다.
- 담아왔던 배열을 뒤집은 것이 LCS이다.
즉, 길이가 변하는 시점이 LCS에 포함되는 부분인 것이다.
LCS는 여러 값이 나올 수 있다.
<< 전체 코드 >>
import sys
input = sys.stdin.readline
a = input().rstrip()
b = input().rstrip()
dp = [[0 for _ in range(len(b)+1)] for _ in range(len(a)+1)]
i, j = 1, 1
while i <= len(a) and j <= len(b):
if a[i-1] == b[j-1]:
dp[i][j] = dp[i-1][j-1] + 1
else:
dp[i][j] = max(dp[i-1][j], dp[i][j-1])
i += 1
if i > len(a):
j += 1
i = 1
answer = []
i, j = len(a), len(b)
while dp[i][j]:
if dp[i-1][j] == dp[i][j]:
i -= 1
elif dp[i][j-1] == dp[i][j]:
j -= 1
else:
answer.append(a[i-1])
i -= 1
j -= 1
print(dp[len(a)][len(b)])
print(''.join(reversed(answer)))
728x90
'코딩테스트 > 백준' 카테고리의 다른 글
[백준 10942] 팰린드롬? - 다이나믹 프로그래밍 (0) | 2023.02.07 |
---|---|
[백준 7579] 앱 - 배낭 문제, 다이나믹 프로그래밍 (0) | 2023.02.06 |
[백준 12865] 평범한 배낭 - 다이나믹 프로그래밍, 배낭 문제 (0) | 2023.02.06 |
[백준 1948] 임계경로 - 위상 정렬, 역추적 (0) | 2023.02.06 |
[백준 5719] 거의 최단 경로 - 다익스트라 알고리즘, bfs 역추적 (0) | 2023.02.05 |