最长单调递增子序列

来源:互联网 发布:mac 硬盘安装助手 编辑:程序博客网 时间:2024/06/15 08:49
最短写法指思路二的第一种写法

问题描述:

给定一个序列X[0···n],找出它的最长的单调递增子序列(Longest Increasing Subsequence)

思路一:

用d[i] 表示以第i个数字为结尾的最长单调递增序列的长度,然后使用
d[i] = max(1, max(d[j] + 1: 1< j< i, a[i]>a[j])) 这个递推关系式计算,用反证法证明正确性,假设所有j < i, a[i] > a[j]的d[j]中,最大下标为max , .同时d[i] > d[max] + 1, 那么将d[i]对应的序列中去掉a[i], 得到的也是递增序列,令最后下标为max2, 那么d[max2] > d[max], 与max为最大递增序列矛盾,得证. 答案就是max(d[j]: j<=n), 时间复杂度为O(n^2)

对应代码:
#include <iostream>#include <cstdio>#include <cstdlib>#include <vector>using namespace std;int LIS(vector<int> &a, int n){    vector<int> f(n);    for(int i = 0; i < n; i++){        f[i] = 1;        for(int j = 0; j < i; j++){            if(a[j] < a[i] && f[j] + 1 > f[i]){                f[i] = f[j] + 1;            }        }    }    int max = 1;    for(int i = 0; i < n; i++){        if(f[i] > max){            max = f[i];        }    }    return max;}int main(){    int n;    vector<int> a(100011);    while(cin >> n){        for(int i = 0; i < n; i++) cin >> a[i];        cout << LIS(a, n) << endl;    }       return 0;}

思路二:

用f[i]表示当前取得长度为i的最长递增序列的时候,该递增序列最后面的数最小的值。比如序列1 2 4 5 3,f[1]=1,f[2]=2,f[3]=3,f[4]=5. 所以f的长度就是结果。同时该题可以有两种写法,一种是std::set的方法, 一种是二分。时间复杂度为O(nlgn)

代码 std::set
int LIS(vector<int> &a, int n){    set<int> f;    set<int>::iterator iter;    int count = 0;    for(int i = 0; i < n; i++){        iter = f.lower_bound(a[i]);        if(iter!= f.end()) {            f.erase(iter);          }        f.insert(a[i]);    }    return f.size();}
代码 二分
int llower_bound(int f[], int n, int key){    int l = 0;    int r = n - 1;    while(l < r){        int m = (l + r) >> 1;        if(f[m] < key){            l = m + 1;        } else {            r = m;        }    }    return l;}int LIS(int* a, int n){    int count = 0;    for(int i = 0; i < n; i++){        if(count == 0 || a[i] > f[count-1]){            f[count] = a[i];            count++;        }else{            f[llower_bound(f,count,a[i])] = a[i];        }    }    return count; // f.size()}
原创粉丝点击