https://www.acmicpc.net/problem/12015
골드 2
수열 A가 주어졌을 때, 가장 긴 증가하는 부분 수열을 구하는 프로그램을 작성하시오.
예를 들어, 수열 A = {10, 20, 10, 30, 20, 50} 인 경우에 가장 긴 증가하는 부분 수열은 A = {10, 20, 10, 30, 20, 50} 이고, 길이는 4이다.
첫째 줄에 수열 A의 크기 N (1 ≤ N ≤ 1,000,000)이 주어진다.
둘째 줄에는 수열 A를 이루고 있는 Ai가 주어진다. (1 ≤ Ai ≤ 1,000,000)
첫째 줄에 수열 A의 가장 긴 증가하는 부분 수열의 길이를 출력한다.
import java.io.*;
import java.util.*;
class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int N = Integer.parseInt(br.readLine());
int[] arr = new int[N];
StringTokenizer st = new StringTokenizer(br.readLine());
for(int i = 0; i < N; i++){
arr[i] = Integer.parseInt(st.nextToken());
}
ArrayList<Integer> lis = new ArrayList<>();
for(int num : arr){
if(lis.isEmpty() || lis.get(lis.size() - 1) < num){
lis.add(num);
}else{
int left = 0;
int right = lis.size() - 1;
while(left < right){
int mid = (left + right) / 2;
if(lis.get(mid) >= num){
right = mid;
}else{
left = mid + 1;
}
}
lis.set(right, num);
}
}
System.out.println(lis.size());
}
}

빈 리스트 LIS 준비
수열의 숫자들을 하나씩 보면서:
=> 결국 LIS에는 진짜 수열은 아니지만 LIS 길이를 구할 수 있는 최소 후보들만 남는다.
입력: 10 20 10 30 20 50
LIS 상태 변화:
[] → 10
[10] → 20
[10, 20] → 10 → 10을 넣을 자리는 0 (바꿔치기)
[10, 20] → 30 → 끝에 붙임
[10, 20, 30] → 20 → 자리는 1 (바꿔치기)
[10, 20, 30] → 50 → 끝에 붙임
최종 LIS 후보: [10, 20, 30, 50] → 길이 = 4