[C++] 백준 12015 - 가장 긴 증가하는 부분 수열 2

2023. 8. 28. 15:15·알고리즘 문제풀이/백준
반응형

<문제 링크> 

https://www.acmicpc.net/problem/12015

 

12015번: 가장 긴 증가하는 부분 수열 2

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

www.acmicpc.net

<알고리즘 분류> 

 - 이분 탐색(Binary Search) 

 - 다이나믹 프로그래밍(Dynamic Programming)

<풀이> 

 - 너무나도 중요한 문제이다. 가장 긴 증가하는 부분수열을 구하는 풀이법은 크게 두 가지가 있다.

첫 번째는 길이가 N인 수열을 돌면서,

"현재의 숫자 앞에서 자신보다 작은 수이면서 가장 큰 부분수열을 가진 값 + 1"

을 구하는 시간복잡도 O(N^2)인 풀이법이 있다.

 

두 번째는 "현재의 숫자 앞에서 자신보다 작은 수이면서 가장 큰 부분수열을 가진 값" 을 수열의 길이를 index로 가지는 배열에 따로 저장해 주어, 이분탐색으로 그 위치를 구한 뒤 갱신하는, 시간복잡도 O(NlogN) 방법이 있다. 

 

이 문제의 경우 수열의 길이 N이 최대 1,000,000이므로, 첫 번째 방식을 적용하면 시간초과가 발생한다. 따라서 두 번째 방법을 쓰기로 한다. 

 

준비물은 이렇다.

  - 수열을 입력받는 vector A,

  - 해당 숫자까지 봤을 때, 가능한 가장 긴 수열의 길이를 저장하는 배열 D (=> Dynamic Programming)

  - ⭐️수열의 최대 길이를 index로 표현한 배열 num.

       (예를 들어, 수열의 최대길이가 j일때, num[j]는 j의 길이를 가진 숫자 중 가장 작은 숫자를 저장한다.)

 

준비물이 완료됐다면, 그림을 통해 이해해 보자. 주어진 수열은 [3, 5, 7, 9, 2, 1, 4, 8] 이다. 

D[i]를 돌 때마다 max값을 갱신해 주면서, 모두 순회를 마쳤다면 max값을 반환하면 된다. 

max_length는 가장 작은 수열의 길이 1(단독)을 항상 만족하기 때문에, max_length=1로 초기화하였다.

<코드> 

#include <iostream>
#include <vector> 
#include <algorithm>
using namespace std;
#define INF 1000001

int N;
vector <int> A;
int num[1000001]; // 수열의 길이를 만족하는 숫자 중 가장 작은 숫자를 저장. 
int D[1000001]; // 해당 숫자까지 보았을 때, 가능한 가장 큰 수열의 길이를 저장. 

int main(){

    cin >> N;
    for (int i=0; i<N; i++){
        int x;
        cin >> x;
        A.push_back(x);
    }
    
    for (int i=1; i<sizeof(num)/sizeof(int); i++){
        num[i] = INF;
    }

    D[0] = 1;
    num[0] = 0;
    num[1] = A[0];
    int max_length = 1;
    for (int i=1; i<N; i++){
        if (D[i] > D[i-1]){
            D[i] = D[i-1] + 1;
            num[D[i]] = min(A[i], num[D[i]]);
        }
        else {
            int index = lower_bound(num, num+sizeof(num)/sizeof(int), A[i]) - num;
            if (index == 0) index ++;
            num[index] = A[i];
            D[i] = index;

        }
        if (D[i] > max_length) max_length = D[i];
         for(int i=0; i<N; i++){
            cout << D[i] << " ";
        }
        cout << "\n"; 
    }

    cout << max_length;
반응형
저작자표시 비영리 변경금지 (새창열림)

'알고리즘 문제풀이 > 백준' 카테고리의 다른 글

[C++] 백준 2143 - 두 배열의 합  (2) 2023.09.03
[C++] 백준 2467 - 용액  (0) 2023.08.29
[C++] 백준 1253 - 좋다  (2) 2023.08.28
[C++] 백준 2110 - 공유기 설치  (0) 2023.08.28
[C++] 백준 1450 - 냅색문제  (1) 2023.08.26
'알고리즘 문제풀이/백준' 카테고리의 다른 글
  • [C++] 백준 2143 - 두 배열의 합
  • [C++] 백준 2467 - 용액
  • [C++] 백준 1253 - 좋다
  • [C++] 백준 2110 - 공유기 설치
jiminai
jiminai
안녕하세요, 고려대학교 컴퓨터학과 학부생의 컴퓨터 공부 기록입니다👻
    반응형
  • jiminai
    컴퓨터 공부 Blog
    jiminai
  • 전체
    오늘
    어제
    • 분류 전체보기 (32)
      • AI Paper Review (9)
        • MLLMs (4)
        • Reinforcement Learning (2)
        • NLP (3)
      • 알고리즘 문제풀이 (18)
        • 백준 (17)
        • 프로그래머스 (1)
        • 알고리즘 이론 공부 (0)
      • AI 개념 정리 (2)
        • Pytorch 공부 (1)
      • Web Development (1)
      • 대외활동&프로젝트&대회 (2)
  • 블로그 메뉴

    • 홈
    • 방명록
    • 프로필
    • Github
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    벡준
    냅색문제
    가장긴증가하는부분수열
    2056
    fasttext
    DP
    dfs
    HACKUTHON 2023
    11000
    2467
    개발
    두 배열의 합
    이분탐색
    다이나믹프로그래밍
    누적합
    BFS
    백준
    Dikjstra
    투포인터
    13975
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
jiminai
[C++] 백준 12015 - 가장 긴 증가하는 부분 수열 2
상단으로

티스토리툴바