https://www.acmicpc.net/problem/9251
LCS (Longest Common Subsequence, 최장 공통 부분 수열)
- 부분 문자열 순서 상관 O
- 연속 X 해도 가능
행렬에 두 문자열 str1
, str2
의 각 부분 문자열 별 LCS 길이 채워나감
=> 행: str1
의 각 문자
=> 열: str2
의 각 문자
=> 행렬의 각 칸: 공통 부분 수열의 길이
한 행씩 맨 앞 문자부터 차례로 비교하여 부분 수열의 길이를 누적해 나감
str1.charAt()
vs "열의 문자" str2.charAt()
를 비교① 두 문자가 같은 경우
[i][j]
을 대각선 왼쪽 윗 칸 [i-1][j-1]의 값 + 1
로 채움② 두 문자가 다른 경우
[i][j]
을 그 이전 칸에 해당하는[i-1][j]
or 왼쪽 칸 [i][j-1]
중에서 더 큰 값으로 채움① 에서 두 문자가 같은 경우, 대각선 왼쪽 위 칸 + 1 값으로 채우는 이유
- "두 문자가 같다" == 두 문자열
str1
,str2
의 각 부분 수열에 대해 공통 원소가 추가됨
ex) 예제에서 "ACAYKP" 의 부분 수열 { A, C } 와 "CAPCAK" 의 부분 수열 { C } 에서
같은 문자 A 가 나타남
=> { A, C, A }, { C, A }
=> 기존 { A, C } 와 { C } 의 공통 부분 수열 길이 1 에서, + 1 을 한 2 가 해당 칸을 채우게 됨
int[][] dp
dp[i][j]
: 문자열 str1
의 [i]
번째 까지의 부분 수열과str2
의 [j]
번째 까지의 부분 수열을 비교했을 때,[0]
행, [0]
열에 패딩을 주어 0
값으로 채움① 두 문자가 같은 경우
dp[i][j] = dp[i-1][j-1] + 1
② 두 문자가 다른 경우
dp[i][j] = max(dp[i-1][j], dp[i][j-1])
int[][] dp
import java.io.*;
public class Main {
static char[] str1;
static char[] str2;
static int len1, len2; // str1, str2 의 길이
static int maxLen; // 출력
static int[][] dp;
static void solution() {
for (int i = 1; i <= len1; i++) {
// 한 행 기준
for (int j = 1; j <= len2; j++) {
if (str1[i - 1] == str2[j - 1]) // 두 문자가 같은 경우
dp[i][j] = dp[i-1][j-1] + 1; // 왼쪽 대각선 윗 칸의 값 + 1
else
dp[i][j] = Math.max(dp[i-1][j], dp[i][j-1]);
// 윗 칸 or 왼쪽 칸 중, 더 큰 값
}
}
maxLen = dp[len1][len2];
}
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(
new InputStreamReader(System.in)
);
str1 = br.readLine().toCharArray();
str2 = br.readLine().toCharArray();
len1 = str1.length;
len2 = str2.length;
dp = new int[len1 + 1][len2 + 1]; // [0]행, [0]열에 각각 패딩 (0 값)
solution();
System.out.println(maxLen);
}
}