Algorithm
[Algo] 백준 12015 가장 긴 증가하는 부분 수열 2 JAVA
조핑구
2024. 5. 8. 13:55
문제 바로가기 : https://www.acmicpc.net/problem/12015
메모리 : 96160KB
시간 : 564ms
언어 : Java 11
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Stack;
import java.util.StringTokenizer;
public class Main {
static int[] arr, vector;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringBuilder sb = new StringBuilder();
int N = Integer.parseInt(br.readLine());
arr = new int[N];
StringTokenizer st = new StringTokenizer(br.readLine());
for (int i = 0; i < N; i++) {
arr[i] = Integer.parseInt(st.nextToken());
}
vector = new int[N];
vector[0] = arr[0];
int end = 0;
for (int i = 0; i < N; i++) {
if (vector[end] < arr[i]) {
vector[++end] = arr[i];
} else {
int reidx = replace(arr[i], 0, end);
vector[reidx] = arr[i];
}
}
System.out.println(end + 1);
}
private static int replace(int num, int left, int right) {
while (left < right) {
int mid = (left + right) / 2;
if (vector[mid] < num) {
left = mid + 1;
} else {
right = mid;
}
}
return right;
}
}
가장 긴 증가하는 부분수열(LIS)는 DP로도 해결이 가능한 문제지만, 수열의 크기가 큰 경우 O(N^2)로 시간초과가 발생하게된다! 따라서 O(N logN)으로 풀 수 있는 방법을 사용해야한다. 이 또한 메모이제이션인데 탐색하는 부분을 이분탐색을 이용해 logN으로 구현이 가능하다.
//수열을 저장할 배열
vector = new int[N];
//맨 처음은 언제나 가장 길지
vector[0] = arr[0];
//맨 마지막 idx
int end = 0;
//arr배열을 돌면서 가장 긴 증가하는 부분수열을 찾아본다.
for (int i = 0; i < N; i++) {
//맨 마지막 수는 가장 커야한다. 지금의 가장 큰 수 보다 arr[i]가 더 크면 이어붙이기
if (vector[end] < arr[i]) {
vector[++end] = arr[i];
} else {
//작으면 이분탐색으로 맞는 위치 찾아서 바꾸기
int reidx = replace(arr[i], 0, end);
vector[reidx] = arr[i];
}
}