https://www.acmicpc.net/problem/9252
이전 시리즈 문제 - 백준 9251, LCS
- 본 문제는 이전 문제 LCS에 출력 값 LCS 문자열 자체를 구하는 과정이 추가됨
- 이전 문제 LCS: 최대 LCS의 문자열 길이(정수 값)만을 출력
- 본 문제 의도 - 점화식에 따라 채워진 DP 배열에서,
"DP 배열을 채우는 역과정을 수행하여 목표 값을 찾아라."
- 백준 9251, LCS 해설
String[][] dp
dp[i][j]
: str1[i]
문자까지와 str2[j]
문자까지에 대한 LCS 문자열dp[str1.length()][str2.lenength()]
str1
의 각 문자, str2
의 각 문자 확인 비교① str1[i]
문자 != str2[j]
문자인 경우
dp[i][j] = max(dp[i-1][j], dp[i][j-1])
② str1[i]
문자 == str2[j]
문자인 경우
dp[i][j] = dp[i-1][j-1] + str1[i]
dp[i-1][j-1]
의 문자열에 동일 문자 str1[i]
추가String[][] dp
: DP 배열메모리 확인
- 대략 최대 (
str1
최대 길이) x (str2
최대 길이) x (LCS
문자열 최대 길이) byte
=> 10^3 x 10^3 x 10^3 byte = 10^9 byte = 10^3 MB >> 256 MB
=> 메모리 초과 !!!
import java.io.*;
public class Main_Memory_Over {
static String str1, str2;
static String LCS;
static String[][] dp;
static void solution() {
for (int i = 1; i <= str1.length(); i++) {
for (int j = 1; j <= str2.length(); j++) {
// str1[i] 문자와 str2[j] 문자가 같은 경우
if (str1.charAt(i-1) == str2.charAt(j-1)) {
if (dp[i-1][j-1] != null)
dp[i][j] = dp[i-1][j-1] + str1.charAt(i-1);
else
dp[i][j] = String.valueOf(str1.charAt(i-1));
}
// str1[i] 문자와 str2[j] 문자가 다른 경우
else {
dp[i][j] = getMaxString(dp[i-1][j], dp[i][j-1]);
}
}
}
LCS = dp[str1.length()][str2.length()];
}
static String getMaxString(String s1, String s2) {
if (s1 == null)
return s2;
else if (s2 == null)
return s1;
return s1.length() > s2.length() ? s1 : s2;
}
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(
new InputStreamReader(System.in)
);
str1 = br.readLine();
str2 = br.readLine();
// [0]행 [0]열은 패딩, [1][1] ~ [len1][len2] 사용
dp = new String[str1.length() + 1][str2.length() + 1];
solution();
StringBuilder sb = new StringBuilder();
if (LCS != null) {
sb.append(LCS.length()).append("\n")
.append(LCS);
}
else {
sb.append("0");
}
System.out.println(sb);
}
}
int[][] dp
dp[i][j]
: str1[i]
문자까지와 str2[j]
문자까지에 대한 LCS 길이dp[len1][len2]
str1
의 각 문자, str2
의 각 문자 확인 비교① str1[i]
문자 != str2[j]
문자인 경우
dp[i][j] = max(dp[i-1][j], dp[i][j-1])
② str1[i]
문자 == str2[j]
문자인 경우
dp[i][j] = dp[i-1][j-1] + 1
dp[i-1][j-1]
의 문자열에 동일 문자 str1[i]
추가DP 배열(각 상태에서의 LCS 길이)을 채운 순서의 역순으로 추적
=> LCS 문자열이 역순으로 저장됨 (결과 값을 역순으로 출력)
마지막 칸 dp[len1][len2]
에서 시작하여, 거슬러 올라가면서 확인
① 현재 칸과 윗 칸 or 왼쪽 칸이 LCS 길이 같은 경우
DP 배열을 채우는 과정에서,
"LCS 길이에 변화가 없다" == "LCS 문자열에 추가된 동일 문자가 없다"
② 현재 칸과 윗 칸, 왼쪽 칸이 LCS 길이 다른 경우 (LCS 길이 감소하는 경우)
"현재 칸에 비해 윗 칸, 왼쪽 칸의 LCS 길이가 줄어들었다"
== DP 배열을 채우는 과정에서, "이전 윗 칸 or 왼쪽 칸으로부터 LCS 문자열에 추가된 동일 문자가 있다"
int[][] dp
: DP 배열int
가능import java.io.*;
public class Main {
static String str1, str2;
static int maxLength; // 출력, LCS 최대 길이
static StringBuilder LCS = new StringBuilder(); // 출력, LCS 문자열
static int[][] dp;
static void solution() {
// 1. DP 배열 채우기
for (int i = 1; i <= str1.length(); i++) {
for (int j = 1; j <= str2.length(); j++) {
// str1[i] 문자 == str2[j] 문자인 경우
if (str1.charAt(i-1) == str2.charAt(j-1))
dp[i][j] = dp[i-1][j-1] + 1;
// str1[i] 문자 != str2[j] 문자인 경우
else
dp[i][j] = Math.max(dp[i-1][j], dp[i][j-1]);
}
}
maxLength = dp[str1.length()][str2.length()];
if (maxLength == 0)
return;
// 2. DP 배열(각 LCS 길이)에서 최종 LCS 구하기
// 마지막 칸 dp[len1][len2]에서 시작하여, 거슬러 올라가면서 확인
int i = str1.length();
int j = str2.length();
while (i != 0 && j != 0) {
// 현재 칸과 윗 칸 or 왼쪽 칸이 LCS 길이 같은 경우
if (dp[i][j] == dp[i-1][j])
i--;
else if (dp[i][j] == dp[i][j-1])
j--;
// 현재 칸과 윗 칸, 왼쪽 칸이 LCS 길이 다른 경우 (LCS 길이 감소하는 경우)
else {
LCS.append(str1.charAt(i-1));
i--;
j--;
}
}
}
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(
new InputStreamReader(System.in)
);
str1 = br.readLine();
str2 = br.readLine();
// [0]행 [0]열은 패딩, [1][1] ~ [len1][len2] 사용
dp = new int[str1.length() + 1][str2.length() + 1];
solution();
System.out.println(maxLength);
if (maxLength > 0)
System.out.println(LCS.reverse()); // 역순
}
}