https://www.acmicpc.net/problem/9252
9252번: LCS 2
LCS(Longest Common Subsequence, 최장 공통 부분 수열)문제는 두 수열이 주어졌을 때, 모두의 부분 수열이 되는 수열 중 가장 긴 것을 찾는 문제이다. 예를 들어, ACAYKP와 CAPCAK의 LCS는 ACAK가 된다.
www.acmicpc.net
LCS 2번을 풀어보겠습니다.
혹시 LCS에 대한 이해가 부족하시거나, LCS 1번 문제를 아직 풀지 않은 분은
https://nodingco.tistory.com/9
[JAVA] 백준 9251번. LCS (골드5)
https://www.acmicpc.net/problem/9251 9251번: LCS LCS(Longest Common Subsequence, 최장 공통 부분 수열)문제는 두 수열이 주어졌을 때, 모두의 부분 수열이 되는 수열 중 가장 긴 것을 찾는 문제이다. 예를 들..
nodingco.tistory.com
이 글을 확인해주시면 감사하겠습니다.
문제는 LCS 1번과 아주 유사합니다. 하지만 단순히 LCS의 길이를 구하는 것 뿐 아니라 LCS의 내용까지 구해야합니다.
쉽게 생각하면 그저 LCS를 구하는 기존의 과정에 더해 여태까지의 String을 저장해도 될 것 같지만, String이 메모리나 연산시간을 많이 잡아먹는걸 감안하면 살짝 위험해 보입니다.
그래서 LCS를 구했던 과정을 역산해서 LCS를 알아내 보겠습니다.
예제의 풀이과정이 기록되는 DP 배열을 실제 표로 나타내어 봅시다. (실제로는 계산의 편의를 위해 좌측과 상단에 0이 들어간 배열이 더 존재합니다.)
A | C | A | Y | K | P | |
C | 0 | 1 | 1 | 1 | 1 | 1 |
CA | 1 | 1 | 2 | 2 | 2 | 2 |
CAP | +1 | 1 | 2 | 2 | 2 | 3 |
CAPC | 1 | +2 | 2 | 2 | 2 | 3 |
CAPCA | 1 | 2 | +3 | 3 | 3 | 3 |
CAPCAK | 1 | 2 | 3 | 3 | +4 | 4 |
정답 LCS인 ACAK는 위와같은 과정을 통해 구해졌다는걸 알 수 있고
최종 정답이 위치한 DP[L2][L1]의 값부터 역순으로 찾아 가는 방법도 알 수 있습니다.
위, 좌측, 대각선 좌상방향 세개의 값을 비교하여
나와 같은 값이 있으면 그 쪽으로, 나와 값이 전부 다를땐 좌상방향으로 이동하면서
그때의 Character를 역순으로 담으면 자연스럽게 답이 찾아집니다.
Stack을 이용해 역순으로 저장하는 방법을 구현하면, 코드는 아래와 같아집니다.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Stack;
public class Main {
public static void main(String[] args) throws NumberFormatException, IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringBuilder sb = new StringBuilder();
Stack<Character> stack = new Stack<Character>();
char[] str1 = br.readLine().toCharArray();
int l1 = str1.length;
char[] str2 = br.readLine().toCharArray();
int l2 = str2.length;
int[][] dp = new int[l2 + 1][l1 + 1];
for (int i = 1; i <= l2; i++) {
char C = str2[i - 1];
for (int j = 1; j <= l1; j++) {
if (C == str1[j - 1]) {
dp[i][j] = dp[i - 1][j - 1] + 1;
} else {
dp[i][j] = Math.max(dp[i][j - 1], dp[i - 1][j]);
}
}
}
sb.append(dp[l2][l1]).append("\n");
int now = dp[l2][l1];
int x = l2;
int y = l1;
while (isIn(x, y) && now > 0) {
if (dp[x - 1][y] == now) {
x--;
} else if (dp[x][y - 1] == now) {
y--;
} else {
x--;
y--;
now--;
stack.push(str1[y]);
}
}
while (!stack.isEmpty()) {
sb.append(stack.pop());
}
System.out.println(sb);
}
static boolean isIn(int x, int y) {
if (0 < x && 0 < y) {
return true;
}
return false;
}
}
주의)
LCS가 0일때 아무것도 출력하지 않아야합니다.
탐색 도중 x와 y가 ArrayIndex를 벗어나는걸 주의해주세요.
'🔍 알고리즘 > 백준 Java' 카테고리의 다른 글
[JAVA] 백준 4600번. 정글의법칙 (실버2) (0) | 2021.11.30 |
---|---|
[JAVA] 백준 2565번. 전깃줄 (실버1) (0) | 2021.11.30 |
[JAVA] 백준 1958번. LCS 3 (골드3) (0) | 2021.11.29 |
[JAVA] 백준 9251번. LCS (골드5) (0) | 2021.11.28 |
[Java] 백준 1000번. A+B (브론즈5) (0) | 2021.11.26 |