最长递增子序列LIS再谈

DP模型:

d(i) 以第 i 个元素结尾的最长递增子序列的长度。

那么就有 d(i) = max(d(j)) + 1;(j<i&&a[j]<a[i]),答案 max(d(i)); 时间复杂度为 O(n*n);

下面介绍一个用二分优化的O(nlogn)的算法。

用一个数组g[i] 表示 d 值为 i 的数的最小的 a;即 最长递增子序列为 i 时,最小的 a 是多少。

显然 g[i]<=g[2]<=g[3];

计算d[i] : 需要找到 g中大于等于a[i] 的第一个数 j ,d[i] = j;

更新g :     g[j] = a[i] ;

使用STL的lower_bound可以直接求出比a[i] 大的第一个数,用的二分查找实现,总时间O(nlogn);

#include <bits/stdc++.h>
using namespace std;

int a[1005];
int b[1005];

int main()
{

    int n;
    scanf("%d",&n);

    for(int i=0;i<n;i++)
        scanf("%d",&a[i]);

    int len = 1;
    b[0] = a[0];

    for(int i=1;i<n;i++) {
        if(a[i]==b[len-1])
            continue;
        if(a[i]>b[len-1])
            b[len++] = a[i];
        else {
            int pos = lower_bound(b,b+len,a[i])-b;
            b[pos] = a[i];
        }
    }

    printf("%d
",len);
    return 0;
}
View Code
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

#define maxn 1005
#define INF 0x3f3f3f3f

int a[1005];
int g[1005];

int binary_search(int *s,int digit,int length) {
    int left = 0,right = length,mid;
    while(right!=left) {
        mid = (left+right)/2;
        if(digit==s[mid])
            return mid;
        else if(digit<s[mid])
            right = mid;
        else left = mid+1;
    }
    return left;
}

int main()
{
    int n;
    scanf("%d",&n);

    for(int i=1;i<=n;i++) {
        scanf("%d",&a[i]);
    }

    memset(g,INF,sizeof(INF));

    g[0] = -1;
    int len = 1;
    int j;
    for(int i=1;i<=n;i++) {
        j = binary_search(g,a[i],len);

        if(j==len)
            len++;
        g[j] = a[i];
    }


    printf("%d
",len-1);
    return 0;
}
View Code



原文地址:https://www.cnblogs.com/TreeDream/p/5988041.html