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는 다른 풀이에 비해 코드 길이가 짧아서 좋은 거 같다
# 결과
'코딩테스트 > 백준 골드' 카테고리의 다른 글
[백준] 1504: 특정한 최단경로 (다익스트라 알고리즘) - JAVA (0) | 2024.10.05 |
---|---|
[백준] 12865: 평범한 배낭 (1/0 Knapsack problem, DP) - JAVA (3) | 2024.10.03 |
[백준] 1916: 최소비용 구하기 (다익스트라 알고리즘) - JAVA (0) | 2024.09.29 |
[백준] 9935: 문자열 폭발 (Stack) - JAVA (0) | 2024.09.20 |
[백준] 14500: 테트로미노 (DFS, dydx) - JAVA (0) | 2024.09.19 |