Algorithm/백준

[백준]9251: LCS(java)

코딩너굴 2022. 3. 23. 21:53
728x90

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

문제

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

예를 들어, ACAYKP와 CAPCAK의 LCS는 ACAK가 된다.

입력

첫째 줄과 둘째 줄에 두 문자열이 주어진다. 문자열은 알파벳 대문자로만 이루어져 있으며, 최대 1000글자로 이루어져 있다.

출력

첫째 줄에 입력으로 주어진 두 문자열의 LCS의 길이를 출력한다.

예제 입력 1

ACAYKP
CAPCAK

예제 출력 1

4

풀이

dp문제이다. dp배열을 담는 과정은 다음과 같이 생각할 수 있다.

자가 현재 서로 같은가? 같다면 +1을 해줘야한다.

처음 C가 같은 순간이다.

이 이후 왜 A, Y, K, P는 C와 다르지만 왜 1이 될까? 는 위 그림을 참고하면 쉽게 이해할 수 있다.

우린 가장 긴 부분 수열을 찾기 때문에 이미 C와 같은 순간 그 뒤에는 모두 일치하지 않아도 답은 1이 되기때문이다.

조금 더 쉽게 단어가 ACAYKP / C 라고 생각하면 쉽게 이해할 수 있다.

위 과정은 다음과 같은 코드로 해결할 수 있다.

이경우도 위의 경우와 같다. A와 같은 순간 A 외의 문자는 같지 않아도 반드시 1이상을 가져야한다.

단어 A / CAPCAK 인 경우로 이해하면 쉽게 이해할 수 있다.

 

여기서 의문 만약 이미 같은 단어가 나온 후 같은 단어를 찾으면 어떻게 처리해줘야할까? 정답은 아래와 같다.

여기서 우리는 이미 C가 같았고 그 후에 A가 또 같은 경우를 만나게 된다.

C가 선택 된 순간

위 과정을 반복하면 아래와 같다.

위 과정을 반복하는 코드는 아래와 같다.

for(int i=1; i<=N; i++) {
    for(int j=1; j<=M; j++) {
        if(str1.charAt(j-1) == str2.charAt(i-1)) {
            dp[i][j] = dp[i-1][j-1] + 1;
        } else {
            dp[i][j] = Math.max(dp[i-1][j], dp[i][j-1]);
        }
    }
}

전체 코드

import java.io.BufferedReader;
import java.io.InputStreamReader;

public class bJ_G5_9251_LCS {
    public static void main(String[] args) throws Exception{
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        String str1 = br.readLine();
        String str2 = br.readLine();

        int M = str1.length();
        int N = str2.length();
        int[][]dp = new int[N+1][M+1];

        for(int i=1; i<=N; i++) {
            for(int j=1; j<=M; j++) {
                if(str1.charAt(j-1) == str2.charAt(i-1)) {
                    dp[i][j] = dp[i-1][j-1] + 1;
                } else {
                    dp[i][j] = Math.max(dp[i-1][j], dp[i][j-1]);
                }
            }
        }
        System.out.printf("%d", dp[N][M]);
    }
}

 

 

728x90