코딩테스트

[BOJ_14002/JAVA]가장 긴 증가하는 부분 수열 4

Eun 2022. 1. 16. 21:11

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

 

14002번: 가장 긴 증가하는 부분 수열 4

수열 A가 주어졌을 때, 가장 긴 증가하는 부분 수열을 구하는 프로그램을 작성하시오. 예를 들어, 수열 A = {10, 20, 10, 30, 20, 50} 인 경우에 가장 긴 증가하는 부분 수열은 A = {10, 20, 10, 30, 20, 50} 이

www.acmicpc.net

문제

풀이

해당 문제는 [가장 긴 증가하는 부분 수열]의 조금 더 심화된 문제이다.

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

 

11053번: 가장 긴 증가하는 부분 수열

수열 A가 주어졌을 때, 가장 긴 증가하는 부분 수열을 구하는 프로그램을 작성하시오. 예를 들어, 수열 A = {10, 20, 10, 30, 20, 50} 인 경우에 가장 긴 증가하는 부분 수열은 A = {10, 20, 10, 30, 20, 50} 이

www.acmicpc.net

최장 증가 부분 수열(LIS)알고리즘을 통해서 위의 문제(11053)를 풀었는데,

이번 문제는 LIS 알고리즘만 가지고는 풀리지 않았다. LIS알고리즘은 가장 긴 수열의 길이만 알 수 있었다.

수열을 출력까지 해야하기때문에 역추적이라는 개념을 사용해서 스택에 저장하고 그것을 출력하는 방식으로 해결하였다.

 

1. 이중 for문을 돌면서 dp[]배열을 채워주었다. 여기서 dp[]배열은 각 인덱스의 값까지 가장 긴 수열의 길이가 저장되어있다. 

i까지 자신이 앞에서 몇번째로 큰 숫자인지 판단하기 위해 for()문을 한개 더 사용하여 j와 i를 비교하도록 하였다.

2. dp배열을 채운 후에 뒤에서 부터 배열을 탐색하면서 역추적을 한다.

3. 지금 현재 가장 긴 수열의 길이(max)와 dp[i]같다면 dp[i]부터 시작한다. 스택에 실제 숫자를 push해준다.

이때 스택을 사용하는 이유는 역추적이기때문에 큰 수부터 집어넣기때문에 스택을 써야 출력할 때 작은 수부터 출력할 수 있기때문이다.

4. 그리고 max를 하나씩 줄이면서 dp[i]의 값와 같은 값을 하나씩 찾고 스택에 집어넣는다.

 

이해를 돕기위해 예를 들자면 {10 20 10 30 20 50}의 dp값은 [1,2,1,3,2,4}이다. max는 dp[5]의 값인 4이다.

dp[i]를 n-1부터 돌다가 max를 만나게 되는 순간부터 스택에 넣는다. dp[5]가 첫번째 경우일 것이고 스택에 입력숫자배열인 num[5]를 넣는다.

그리고 max--를 하면 max는 3가 되고 dp[3]이 이에 해당한다. 그러면 또 스택에 num[3]을 집어넣는다. 

그러면 스택에는 [50 30 20 10] 까지 들어가 있는 상태!

 

5. 스택이 빌 때까지 출력을 하면 완료!

 

코드

package Week07;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Stack;
import java.util.StringTokenizer;

public class BOJ14002 {

	public static void main(String[] args) throws NumberFormatException, IOException {
		// TODO Auto-generated method stub
		
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringBuilder sb = new StringBuilder();
		
		int n = Integer.parseInt(br.readLine());
	
		StringTokenizer st = new StringTokenizer(br.readLine());
		
		int num[]=new int[n];
		int dp[]=new int[n];
		
		for(int i=0;i<n;i++) {
			num[i]=Integer.parseInt(st.nextToken());
		}
		
		for(int i=0;i<n;i++) {
			dp[i]=1;
			
			for(int j=0;j<i;j++) {
				if(num[i]>num[j] && dp[j]+1>dp[i]) {
					dp[i]=dp[j]+1;
				}
			}
		}
		
		
		int max=dp[0];
		for(int i=0;i<n;i++) {
			if(max<dp[i]) {
				max=dp[i];
			}
		}
		sb.append(max+"\n");
		
		Stack<Integer> stack = new Stack<>();
		// dp역추적
		for(int i=n-1;i>=0;i--) {
			if(dp[i]==max) {
				stack.push(num[i]);
				max--;
			}
		}
		while(!stack.isEmpty()) {
			sb.append(stack.pop()+" ");
		}
		
		System.out.println(sb);

	}

}