알고리즘

[알고리즘] 백준 11053 자바 JAVA 동적프로그래밍 LIS 최장 증가 수열

행복하개! 2020. 10. 20. 14:29

 

 

 

정말 알것 같다 싶으면 새로운 유형이 나와버리는 동적프로그래밍이다! 조금씩 익숙해지고는 있지만 자잘한 조건에 난감한 경우가 많다. 

 

이 문제는 LIS문제이다. 이걸 처음 접하면 이게 왜 동적 프로그래밍 문제지? 하고 의문을 가지고 내 식대로 풀다가 망하는 경우가 100% 된다. 

 

망하는 이유는 문제를 정확히 이해하지 못했기 때문이다. 아래는 문제에서 주어진 조건이다.

6
10 20 10 30 20 50

이렇게 보면 그냥 처음부터 max값을 찾아서 10 20 넣고 10은 건너뛰고 30넣고 20은 건너뛰고 50넣고.. 이렇게 하면 될것 같다. 

 

그래서 아래는 그렇게 짠 코드이다.

public class BaekJoon_16_11053_2 {

	public static void main(String[] args) throws NumberFormatException, IOException {
		BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
		BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(System.out));

		int n = Integer.parseInt(reader.readLine());

		int[] A = new int[1001];
		
		A[0] = Integer.MIN_VALUE;
		StringTokenizer st = new StringTokenizer(reader.readLine());
		for (int i = 1; i <= n; i++) {
			A[i] = Integer.parseInt(st.nextToken());
		}

		List<Integer> dp = new ArrayList<Integer>();
		dp.add(A[1]);
		int max = Integer.MIN_VALUE;
		for (int i = 2; i <= n; i++) {
			if (max < A[i]) {
				max = A[i];
				dp.add(A[i]);
			}
		}

		writer.write(dp.size() + "");

		writer.flush();
		reader.close();
		writer.close();
	}

}

근데 .. 이 코드의 문제점은 무조건 처음부터 시작해서 더 이상 큰값이 나오지 않으면 그걸로 끝인 코드이다. 그게 무슨말이냐면, 아래의 조건을 보자

10
1 5 2 1 4 3 4 5 2 1

이 조건을 기준으로 저 코드에 대입해보면 1다음에 5가 나오고 5이상으로 큰 값이 뒤에 없기 때문에 그대로 2가 출력된다. 하지만 이 문제는 최장길이를 구하는 문제이다. 왼쪽에서 가까이있는걸 푸는 문제가 아니다. 가장 길이가 긴 부분 수열을 찾는 것이다.

즉 2가아니고,

 

1 5 2 1 4 3 4 5 2 1, 즉 5가 된다. 

 

처음부터 max값으로 비교하는 문제가 아니라는 뜻이다. 처음에 문제를 정확히 이해하지 못하고 마구잡이로 풀었는데, 

그래서 최장 증가 수열 문제이다.

 

 

 

근데 그 원리만 정확히 알고나면 어려울 건 전혀 없다.. 그냥 하나의 로직이다.

 

아래는 구현 코드이다.

 

public class BaekJoon_16_11053 {

	public static void main(String[] args) throws NumberFormatException, IOException {
		BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
		BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(System.out));

		int n = Integer.parseInt(reader.readLine());

		int[] A = new int[1001];
		int[] dp = new int[1001];

		A[0] = Integer.MIN_VALUE;
		StringTokenizer st = new StringTokenizer(reader.readLine());
		for (int i = 1; i <= n; i++) {
			A[i] = Integer.parseInt(st.nextToken());
		}

		dp[0] = 0;
		dp[1] = 1;
		for (int i = 2; i <= n; i++) {
			dp[i] = 1; // 기준 최저인 1로 설정해두고 큰값나올때마다 수정
			for (int j = 1; j < i; j++) {
				if (A[i] > A[j])
					dp[i] = Math.max(dp[j] + 1, dp[i]); // 지금것보다 크면 계속 업데이트
			}
		}

		int max = Integer.MIN_VALUE;
		for (int i = 1; i <= n; i++) {
			if (max < dp[i])
				max = dp[i];
		}
		writer.write(max + "");

		writer.flush();
		reader.close();
		writer.close();
	}

}

 

화이또!