9251번: LCS
LCS(Longest Common Subsequence, 최장 공통 부분 수열)문제는 두 수열이 주어졌을 때, 모두의 부분 수열이 되는 수열 중 가장 긴 것을 찾는 문제이다. 예를 들어, ACAYKP와 CAPCAK의 LCS는 ACAK가 된다.
www.acmicpc.net
논리
- 두 문자열 s1, s2의 끝자리가 같다면 lcs(s1, s2)는 lcs(s1[:-1], s2[:-1]) + 1과 같다 (마지막 문자가 같으므로 이를 제외한 것들의 lcs에서 1을 더함)
- 두 문자열 sl, s2의 끝자리가 다르다면 lcs(s1, s2)는 lcs(s1, s2[:-1])과 lcs(s1[:-1], s2) 중 큰 값을 취한다
- 공통 문자열을 확인하고 싶다면 lcs_table을 거꾸로 탐색하면서 올라갈 때 (1)의 경우인 문자를 기록한다
코드
import sys
def LCS():
# lcs를 구하기 위해 dp table을 채우는 함수
def get_lcs_table():
table = [[0] * (m + 1) for _ in range(n + 1)]
for i in range(1, n+1):
for j in range(1, m+1):
if s1[i-1] == s2[j-1]:
table[i][j] = table[i-1][j-1] + 1
else:
table[i][j] = max(table[i][j-1], table[i-1][j])
return table
# dp table을 역추적하여 공통문자열을 찾아내는 함수
def get_lcs():
n = len(lcs_table) - 1
m = len(lcs_table[0]) - 1
lcs = []
while lcs_table[n][m] > 0 and n > 0 and m > 0:
# dp table에서 같은 숫자가 안나올때까지 이동
while lcs_table[n][m-1] == lcs_table[n][m]: m -= 1
while lcs_table[n-1][m] == lcs_table[n][m]: n -= 1
# 해당 문자 기록
lcs.append(s1[n-1])
# 이 상태에서 좌상향으로 이동
m -= 1
n -= 1
# 역순으로 반환
return "".join(lcs[::-1])
# inputs
s1 = sys.stdin.readline().strip()
s2 = sys.stdin.readline().strip()
n, m = len(s1), len(s2)
lcs_table = get_lcs_table()
lcs = get_lcs()
# LCS 길이 출력
print(lcs_table[n][m])
# LCS 문자열 출력
print(lcs)
return
LCS()
'dev > 알고리즘문제풀이' 카테고리의 다른 글
[ 백준 12865번 ] 아주 평범한 배낭 파이썬 (0) | 2021.09.01 |
---|---|
[ 백준 11049번 ] 행렬 곱셈 순서 파이썬 (1) | 2021.09.01 |
[ 백준 11053번 ] 가장 긴 증가하는 부분 수열(LIS) 파이썬 (0) | 2021.09.01 |
[ 백준 2573번 ] 빙산 파이썬 (0) | 2021.08.25 |
[ 백준 2623번 ] 음악프로그램 파이썬 (1) | 2021.08.25 |