카테고리 없음

[백준/JAVA] 14003번: 가장 긴 증가하는 부분 수열 5

imname1am 2023. 5. 17. 21:56
반응형

🔺 문제

 

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

첫째 줄에 수열 A의 크기 N (1 ≤ N ≤ 1,000,000)이 주어진다. 둘째 줄에는 수열 A를 이루고 있는 Ai가 주어진다. (-1,000,000,000 ≤ Ai ≤ 1,000,000,000)

www.acmicpc.net

 

 

🔺 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
import java.util.*;
import java.io.*;
 
public class Main {
    static int N, maxLen;
    static int B[] = new int[1000001];     // 현재 가장 유리한 증가 수열 저장
    static int A[] = new int[1000001];     // 수열 데이터 저장
    static int D[] = new int[1000001];     // 0 ~ i까지 i를 포함하는 최장 증가 수열 길이 저장
    static int ans[] = new int[1000000];   // 정답 수열 저장
    
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st;
        
        N = Integer.parseInt(br.readLine());
        
        st = new StringTokenizer(br.readLine()," ");
        for(int i = 1 ; i <= N ; i++) {
            A[i] = Integer.parseInt(st.nextToken());
        }
        
        int idx;
        B[++maxLen] = A[1];
        D[1= 1;
        
        for(int i = 2 ; i <= N ; i++) {
            // 가장 마지막 수열보다 현재 수열이 클 때
            if(B[maxLen] < A[i]) {
                B[++maxLen] = A[i]; // B 배열 끝에 A[i] 값 추가
                D[i] = maxLen;
            }
            else {
                // B 배열에서 data[i]보다 첨으로 크거나 같아지는 원소의 idx 찾기
                idx = binarySearch(1, maxLen, A[i]);
                B[idx] = A[i];  // 현재 수열 값 저장
                D[i] = idx;
            }
        }
        
        System.out.println(maxLen); // 가장 긴 증가하는 부분의 수열 길이 출력
        idx = maxLen;
        
        // 뒤에서부터 탐색하면서 정답 수열 저장
        int x = B[maxLen] + 1;
        for(int i = N ; i >= 1 ; i--) {
            if(D[i] == idx && A[i] < x) {
                ans[idx] = A[i];
                x = A[i];
                idx--;
            }   
        }
        
        // 저장된 정답 배열 출력
        for(int i = 1 ; i <= maxLen ; i++) {
            System.out.print(ans[i] + " ");
        }
    }
    
    // 이분탐색 : 현재 수열이 들어갈 수 있는 위치 빠르게 찾기
    static int binarySearch(int l, int r, int now) {
        int mid;
        
        while(l < r) {
            mid = (l + r) / 2;
            if(B[mid] < now)
                l = mid + 1;
            else
                r = mid;
        }
        return l;
    }    
}
cs
✅ 해결 아이디어
✔ 이분 탐색을 이용한 LIS 구하기 ! 
- 시간 복잡도 : O(N log N) (∵ 수열 크기)

 

데이터 개수가 많아서 DP방식은 시간이 오래 걸려 사용하지 못하고 O(N^2),

이분 탐색을 사용하는 것이라 함

 

설명은.. 나보다 다른 분들이 더 잘해주시니까..

그거 보고 이해할 수 있었다..

 

 

💥 유의사항

: 이분 탐색에 의해 만들어진 리스트가 LIS를 구성하는 요소들은 아님

 


🔺 다른 풀이들

- 과정 설명 덕분에 이해가 되었다..ㅠㅠㅠ

 

[백준 14003] 가장 긴 증가하는 부분 수열 5 (JAVA)

https://www.acmicpc.net/problem/14003최장 증가 부분 수열(LIS, Longest Increasing Subsequence)을 이용하여 해결할 수 있습니다.arr : 1, 2, 6, 4, 2, 5, 3, 7, 9 dp : \[]최

velog.io

 

- 배열 대신 리스트와 스택을 활용하셨다. 복습할 때 코드는 셋 중 하나로  연습해야곘따

 

[백준 14003: JAVA] 가장 긴 증가하는 부분 수열 5/ 이분 탐색+ 역추적

개요 이 문제는 이분 탐색으로 풀이할 수 있다. (dp로는 입력의 최댓값이 너무 커서 시간 초과가 날 것이다.) 시간은 O(nlog(n))이 될 것이다. 사실 이 문제는 기존의 아래 문제에서 경로의 개념만 추

dragon-h.tistory.com

 

[BOJ 백준] 가장 긴 증가하는 수열5 (14003) Java

링크 : https://www.acmicpc.net/problem/14003 문제 설명 : 더보기 수열 A가 주어졌을 때, 가장 긴 증가하는 부분 수열을 구하는 프로그램을 작성하시오. 예를 들어, 수열 A = {10, 20, 10, 30, 20, 50} 인 경우에 가

subbak2.com

 

[java] 백준 14003 (가장 긴 증가하는 부분 수열 5) Gold 1

문제 원문 링크 : https://www.acmicpc.net/problem/14003 14003번: 가장 긴 증가하는 부분 수열 5 첫째 줄에 수열 A의 크기 N (1 ≤ N ≤ 1,000,000)이 주어진다. 둘째 줄에는 수열 A를 이루고 있는 Ai가 주어진다. (-1

gre-eny.tistory.com


💬 느낀 점

처음에 모지... 싶었는데 잘 설명해주신 다른 분들 덕분에 이해할 수 있었다....

압도적 감사....

 

 

보니까 시리즈 문제들도 있던데 얘네도 풀면서 익숙해져봐야겠다!

 

1회독 2회독 3회독 4회독 5회독
V 7/10      

 

 

(+7/10 2회독)

우왕 모르겠다... 아래 글 참고했다

 

[BOJ 백준] 가장 긴 증가하는 수열5 (14003) Java

링크 : https://www.acmicpc.net/problem/14003 문제 설명 : 더보기 수열 A가 주어졌을 때, 가장 긴 증가하는 부분 수열을 구하는 프로그램을 작성하시오. 예를 들어, 수열 A = {10, 20, 10, 30, 20, 50} 인 경우에 가

subbak2.com

이 문제 시리즈 아직도 안 풀어봐서 얘네 이번엔 진짜 풀어봐야겠다

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
import java.util.*;
import java.io.*;
 
public class Main {
    static int N;
    static int[] input, index;   // index[1] : input[1]가 LIS에 들어간 위치
    static ArrayList<Integer> LIS;
    
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
 
        N = Integer.parseInt(br.readLine());
        input = new int[N + 1];
        index = new int[N + 1];
        LIS = new ArrayList<Integer>();
        
        StringTokenizer st = new StringTokenizer(br.readLine(), " ");
        for(int i = 1 ; i <= N ; i++) {
            input[i] = Integer.parseInt(st.nextToken());
        }
        
        if(N == 1) { // N이 1이면 바로 끝내기
            bw.write("1\n" + input[1]);
            bw.flush();
            bw.close();
            br.close();
            return;
        }
        
        LIS.add(input[1]);
        index[1= 0;
        
        // 2. 이진탐색을 활용한 LIS 배열 만들기 🔔
        for(int i = 2 ; i <= N ; i++) {
            if(input[i] > LIS.get(LIS.size() - 1)) {    // 값이 더 큰 경우
                LIS.add(input[i]);
                index[i] = LIS.size() - 1;
            }
            else {
                binarySearch(i);
            }
        }
        
        // 3. 정답 출력
        StringBuilder sb = new StringBuilder();
        sb.append(LIS.size() + "\n");
        
        // 💥 역추적 경로 저장할 Stack
        Stack<Integer> stack = new Stack();
        
        int findId = LIS.size() - 1;
        for(int i = N ; findId >= 0 && i > 0 ; i--) {
            if(index[i] == findId) { // 찾길 원하는 인덱스와 같은 경우,
                findId--; // 찾길 원하는 인덱스 하나 감소시키고
               stack.push(input[i]); // 스택에 경로 추가 (다음 인덱스 값을 찾기 위해)
            }
        }
        
        while(!stack.isEmpty()) { // 스택에서 꺼내며 탐색
            sb.append(stack.pop()).append(" ");
        }
        bw.write(sb.toString());
        bw.flush();
        bw.close();
        br.close();
    }
    
    private static void binarySearch(int id) {
        int start, end, mid;
        start = 0;
        end = LIS.size() - 1;
        
        while(start < end) {
            mid = (start + end) / 2;
            // 값이 더 크면, lower bound 로직
            if(LIS.get(mid) >= input[id]) {
                end = mid;
            }
            else {
                start = mid + 1;
            }
        }
        
        // LIS 배열 갱신하고, 위치 기록
        LIS.set(start, input[id]);
        index[id] = start; // 리스트에 자신의 위치 기록
    }
}
 
cs

 


(참고)

✔ Do it 알고리즘 코딩테스트 자바편

 

반응형