[BOJ] 9252번: LCS 2 (Python)

2022. 10. 17. 20:54·Algorithm
백준 9252번: LCS 2
Dynamic Programming

https://www.acmicpc.net/problem/9252

 

9252번: LCS 2

LCS(Longest Common Subsequence, 최장 공통 부분 수열)문제는 두 수열이 주어졌을 때, 모두의 부분 수열이 되는 수열 중 가장 긴 것을 찾는 문제이다. 예를 들어, ACAYKP와 CAPCAK의 LCS는 ACAK가 된다.

www.acmicpc.net

1. 문제 설명

이 문제는 LCS를 구하는 과정이 백준 9521번과 완전히 동일하다. (Input, Output 형식도 같다!)

따라서, LCS를 구하는 방법에 대해서는 이전 글을 참고하면 된다.

https://lucple.tistory.com/31

 

만약 문자열 X와 Y가 다음과 같다고 하자.

X = <A, C, A, Y, K, P>
Y = <C, A, P, C, A, K>

위의 예제에서 생성될 수 있는 LCS는 <A, C, A, K>이고, 길이는 4이다.

따라서 첫째 줄에 LCS의 길이인 4, 둘째 줄에 LCS인 ACAK를 출력하면 된다.

 


2. 문제 접근

이 글에서는 LCS를 구하는 과정에 대해서만 설명할 것이다.

LCS의 길이는 Dynamic Programming으로 2차원 배열을 잘 채우면..

 

물론 LCS를 구하기 위해서 Dynamic Programming를 한 번 더 사용할 것이다.

이전과 다른 것은 시작점의 위치이다.

LCS의 길이를 구하는 과정에서 X0과 Y0부터 비교하여 차례대로 nested loop를 돌았으나,

이번에는 Xn과 Ym에서 시작하여 두 문자열중 하나의 길이가 0일때까지 거꾸로 올라갈 것이다.

 

LCS의 길이를 채운 테이블을 dp[i][j]이라 하자. (문자열 X의 길이는 i, 문자열 Y의 길이는 j이다.)  

case 1) dp[i][j] == dp[i-1][j]인 경우 : Xi-1와 Yj을 비교한 값이 Xi와 Yj을 비교한 값과 같음을 의미하므로

Xi와 Yj가 같지 않은 경우이다. 따라서 i를 하나 감소시킨다.

 

case 2) dp[i][j] == dp[i][j-1]인 경우 : Xi와 Yj-1을 비교한 값이 Xi와 Yj을 비교한 값과 같음을 의미하므로

Xi와 Yj가 같지 않은 경우이다. 따라서 j를 하나 감소시킨다.

 

case 3) 위의 두 케이스에 해당하지 않는다면 Xi와 Yj가 같은 경우에 해당한다.

Xi와 Yj가 같으면 당연히 dp[i-1][j]와 dp[i][j-1]보다 클 것이기 때문이다. (2차원 배열을 그러한 규칙으로 채웠으니까!)

따라서 Xi (=Yj)를 출력하고, i와 j를 모두 하나씩 감소시킨다.

 

위의 case를 이용하여 dp[i][j] == 0일때까지 반복하면 된다.

따라서 시간복잡도는 O(n+m)이 될 것이다. (두 문자열의 길이의 합만큼 2차원 배열을 탐색하면 끝!)

 


3. 구현 코드

from sys import stdin, setrecursionlimit
setrecursionlimit(10**6)

def back_print(i, j):
    if dp[i][j] == 0:
        return

    if dp[i][j] == dp[i - 1][j]:
        back_print(i - 1, j)
    elif dp[i][j] == dp[i][j - 1]:
        back_print(i, j - 1)
    else:
        back_print(i - 1, j - 1)
        print(X[i - 1], end='')  # Y[j - 1]을 출력해도 같은 결과!


X = stdin.readline().strip()
Y = stdin.readline().strip()
len1, len2 = len(X) + 1, len(Y) + 1
dp = [[0] * len2 for _ in range(len1)]

for i in range(1, len1):
    for j in range(1, len2):
        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])
            
print(dp[-1][-1])

back_print(len1 - 1, len2 - 1)

만약 예제가 다음과 같다면, dp는 아래와 같다.

ACAYKP
CAPCAK

이때 빨간색은 LCS(출력해야 하는 값)을 나타내고, 파란색은 백트래킹 과정에서 이동하는 경로를 나타낸다.

    A C A Y K P
  0 0 0 0 0 0 0
C 0 0 1 1 1 1 1
A 0 1 1 2 2 2 2
P 0 1 1 2 2 2 3
C 0 1 2 2 2 2 3
A 0 1 2 3 3 3 3
K 0 1 2 3 3 4 4

 

 

 

'Algorithm' 카테고리의 다른 글
  • [LeetCode] 1706. Where Will the Ball Fall (Python)
  • [LeetCode] 3. Longest Substring Without Repeating Characters (Python)
  • [BOJ] 1012번: 유기농 배추 (Python)
  • [BOJ] 9251번: LCS (Python)
Bookish
Bookish
Waking Up Early :P / Ajou Univ
  • Bookish
    토끼의 발자취
    Bookish
  • 전체
    오늘
    어제
    • 분류 전체보기 (64)
      • GDSC Ajou (9)
      • Algorithm (15)
      • Lab (2)
      • Challenge (11)
      • Event (3)
      • Tips (4)
      • Daily (12)
      • 병원 (8)
  • 블로그 메뉴

    • Solved.ac
    • LeetCode
    • Kaggle
    • Manage
    • 홈
    • 태그
    • 미디어로그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    GDSC
    라식
    리트코드
    leetcode
    라섹
    Daily LeetCoding Challenge
    Python
    파이썬
    아주대학교 프로그래밍 경시대회
    백준
    빅데이터분석기사
    Google Solution Challenge 2023
    ㅅㅅ안과
    라섹후기
    삼성안과
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
Bookish
[BOJ] 9252번: LCS 2 (Python)
상단으로

티스토리툴바