[SWEA] 3307. 최장 증가 부분 수열

LIS DP방법

  • 메모리 : 28,152 KB
  • 실행시간 : 152 ms
  • 코드길이 : 1,150 B
  • 소요시간 : 10M
  • 이제야 원리를 완전히 이해했다. 제일 아래의 코드보다 이 코드가 더욱 이해하기에 도움이 되는 것 같다. NlogN방법이 기억이 안날때는 이 코드는 작성할 수 있을 것 같다.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

public class Solution_D3_3307_최장증가부분수열_LIS_DP {

	static int N, num[], lis[];

	public static void main(String[] args) throws NumberFormatException, IOException {
		BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
		StringBuilder answer = new StringBuilder();
		int T = Integer.parseInt(in.readLine());
		for (int tc = 1; tc < T + 1; tc++) {
			N = Integer.parseInt(in.readLine());
			num = new int[N];
			lis = new int[N];
			StringTokenizer st = new StringTokenizer(in.readLine(), " ");
			for (int i = 0; i < N; i++) {
				num[i] = Integer.parseInt(st.nextToken());
			}

			// LIS DP방법
			int maxIndex = 0;
			for (int i = 0; i < N; i++) {
				lis[i] = 1; // lis배열 초기화
				for (int j = 0; j < i; j++) {
					if (num[i] > num[j] && lis[i] < lis[j] + 1) {
						lis[i] = lis[j] + 1;
						if (lis[maxIndex] < lis[i])
							maxIndex = i;
					}
				}
			}
			answer.append('#').append(tc).append(' ').append(lis[maxIndex]).append('\n');
		} // end test-case;
		System.out.print(answer);
		in.close();
	} // end main
}

LIS 이진탐색 방법 (NlogN)

  • 메모리 : 21,576 KB
  • 실행시간 : 127 ms
  • 코드길이 : 1,074 B
  • 소요시간 : 10M
  • 경로를 출력하는 코드는 아니고 길이만 구하는 코드!
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.StringTokenizer;

public class Solution_D3_3307_최장증가부분수열_LIS_NlogN {

	static int N, num[], lis[];

	public static void main(String[] args) throws NumberFormatException, IOException {
		BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
		StringBuilder answer = new StringBuilder();
		int T = Integer.parseInt(in.readLine());
		for (int tc = 1; tc < T + 1; tc++) {
			N = Integer.parseInt(in.readLine());
			num = new int[N];
			lis = new int[N];
			StringTokenizer st = new StringTokenizer(in.readLine(), " ");
			for (int i = 0; i < N; i++) {
				num[i] = Integer.parseInt(st.nextToken());
			}

			// LIS 이진탐색방법
			int size = 0, temp;
			for (int i = 0; i < N; i++) {
				temp = -(Arrays.binarySearch(lis, 0, size, num[i])) - 1;
				lis[temp] = num[i];
				if (temp == size)
					++size;
			}
			answer.append('#').append(tc).append(' ').append(size).append('\n');
		} // end test-case;
		System.out.print(answer);
		in.close();
	}

}

LIS_NlogN 방법

  • 메모리 : 21,180 KB
  • 실행시간 : 129 ms
  • 코드길이 : 1,656 B
  • 소요시간 : 20 M
  • 위와 같은 코드이지만 위 코드가 나한테는 더 이해가 쉽다.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

public class Solution_D3_3307_최장증가부분수열 {

	public static void main(String[] args) throws NumberFormatException, IOException {
		BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
		StringBuilder answer = new StringBuilder();
		int T = Integer.parseInt(in.readLine());
		for (int tc = 0; tc < T; tc++) {
			answer.append('#').append(tc + 1).append(' ');
			int N = Integer.parseInt(in.readLine());
			int[] numbers = new int[N];
			StringTokenizer st = new StringTokenizer(in.readLine(), " ");
			for (int i = 0; i < N; i++) {
				numbers[i] = Integer.parseInt(st.nextToken());
			} // end input

			int[] C = new int[N];
			int[] path = new int[N];
			int size = 0;

			path[size] = -1;
			C[size++] = 0;
			for (int i = 1; i < N; i++) {
				if (numbers[C[size - 1]] < numbers[i]) {
					path[i] = C[size - 1];
					C[size++] = i;
				} else {
					int temp = binarySearch0(numbers, C, 0, size, numbers[i]);
					if (temp < 0)
						temp = -temp - 1;
					path[i] = path[C[temp]];
					C[temp] = i;
				}
			}

			answer.append(size).append('\n');
		} // end test case

		System.out.println(answer);
		in.close();
	} // end main

	private static int binarySearch0(int[] numbers, int[] c, int fromIndex, int toIndex, int key) {
		int low = fromIndex;
		int high = toIndex - 1;

		while (low <= high) {
			int mid = (low + high) >>> 1;
					int midVal = numbers[c[mid]];

					if (midVal < key)
						low = mid + 1;
					else if (midVal > key)
						high = mid - 1;
					else
						return mid;
		}
		return -(low + 1);
	}

}

Leave a comment