성장일기

내가 보려고 정리하는 공부기록

코딩테스트/백준 골드

[백준] 9251: LCS (이차원 배열을 이용한 DP) - JAVA

와나나나 2024. 10. 2. 09:35
728x90

class 4

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

 

 

 

 

# 문제 

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

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

 

# 예제 

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

ACAYKP
CAPCAK

 

출력 

4

 

 

# 필요개념 

문제를 보고 dp를 사용해야겠다는 생각을 했지만, 점화식을 어떻게 세워야 할지 계속 고민이 되었다. 1차원 배열을 이용해 점화식을 세우고, 문제를 푸는 것은 익숙하지만 그 외의 방법은 익숙하지 않은 거 같다.

 

원래는 길이가 더 짧은 문자열을 str1, 나머지를 str2로 지정하고, str1을 기준으로 두고 str2을 순회하여 문자가 같을 때 해당 인덱스를 dp에 저장하는 방식으로 하려 했다. 그러나 이렇게 풀 때의 문제는 같은 문자가 여러개 나올 경우 어떻게 처리해야하느냐였다. 그래서 더 고민을 하다가 다른 사람들의 풀이를 참고하였다.

 

그중 대부분은 dp를 이차원 배열로 지정하셨고, 그걸 보니 이전에 비슷한 방식으로 푼 문제가 생각나서 풀이를 시작하였다. 

 

큰 기준은 아래와 같다.

  • 만약 str1의 문자 == str2의 문자 라면,  이전 dp값 + 1 처리를 한다. 
    • 처음엔 Math.max를 이용해 현재 칸의 i-1값과 j-1값 중 큰 값을 구한 후 거기에 + 1하고자 했다.
    • 그러나 그럴 필요 없이 대각선 값 (i - 1, j - 1) 에 + 1 해주면 된다.
  • 만약 같지 않으면 이전 칸의 값을 그대로 가져온다.
    • 이 경우야 말로 Math.max로 i-1값과 j-1 값 중 큰 값을 가져와 대입한다.

 

i - 1과 j -1 을 사용해야 하기 때문에 dp배열의 크기를 dp[N+1][M+1]로 잡고 1~N 인덱스를 사용하였다.

 

 

# Code

import java.io.*;
import java.util.*;
import static java.lang.Math.*;
public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String str1 = br.readLine();
        String str2 = br.readLine();
        int[][] dp = new int[str1.length() + 1][str2.length() + 1];

        for (int i = 1 ; i <= str1.length() ; i++) {
            for (int j = 1 ; j <= str2.length() ; j++) {
                if (str1.charAt(i - 1) == str2.charAt(j - 1)) {
                    dp[i][j] = dp[i - 1][j - 1] + 1;
                } else {
                    dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
                }
            }
        }
        System.out.println(dp[str1.length()][str2.length()]);
    }
}

 

dp는 다른 풀이에 비해 코드 길이가 짧아서 좋은 거 같다

 

# 결과