LIS(Longest Increasing Subsequence)

Updated:

원소 $N$개인 배열의 일부 원소를 골라 증가하는 부분 수열을 이룰 때, 가장 긴 증가하는 부분 수열의 길이를 구하는 코드를 작성하라

LIS 알고리즘의 구현


만약 {1,2,4,5,3,4,5}인 $a$배열이 주어졌을 때 {1,2,3,4,5}의 부분 수열의 길이가 5인 수열이 LIS의 길이가 된다.

DP를 이용하면 쉽게 구현할 수 있다.

  • $dp[i]$ : $i$번째 원소까지 부분 수열을 체크했을 때 최장 길이
vector<int> a(len);
int dp[len];

int LIS() {
    dp[0]=0;
    int lis=0;
    for(int i=0;i<len;i++) {
        dp[i]=1; // 기본 길이
        for(int j=0;j<i;j++) {
            if(a[i]>a[j] && dp[j]+1>dp[i]) {
                dp[i]=dp[j]+1;
            }
        }
        lis=max(lis,dp[i]);
    }
    return lis;
}

그러나 위의 코드는 이중 for문 때문에 $O(N^2)$의 시간 복잡도를 가지게 된다.

그래서 이분탐색을 통해 시간 복잡도를 줄이고자 한다.

이분탐색을 통해 LIS를 유지하기 위한 최적의 위치에 원소를 삽입하는 방법을 사용할 수 있다.

vector<int> a(len);
int lis() {
    vector<int> v;
    v.push_back(-INF); // 최소 길이는 1로 맞추기 위해
    for(auto it : a) {
        if(v.back()<it) { // 증가하는 수라면 뒤에 삽입
            v.push_back(it);
        }
        else { // 증가하지 않는 수라면 lower_bound로 삽입시킬 위치를 찾고 치환한다
            auto it=lower_bound(v.begin(),v.end(),it);
            *it=x;
        }
    }
    return v.size();
}

위의 코드는 $a$배열의 크기 $N$을 도는 for문이 있고 그 안에 $v$를 이분 탐색하는 코드가 존재한다. 따라서 $O(NlogN)$의 시간 복잡도를 가진다.

Tags:

Categories:

Updated:

Comments