最长上升子序列

最长上升子序列,众所周知,是dp的经典问题。用简单的dp解决的复杂度是O(n方),用dp+二分的方法解决的复杂度是O(nlogn).

1、转移方程:

MaxLen (1) = 1

MaxLen (k) = Max { MaxLen (i):1<i < k 且 ai < ak且 k≠1 } + 1


2、

假定存在一个序列d[1...9]=2 1 5 3 6 4 8 9 7,可以看出LIS长度为5。现在开始一步一步的找出来最终的结果。

定义序列B,令i=1...9来逐个考察。此外用变量len来记录现在最长算到了多少了。

首先,把d[1]放到B里,即B[1]=d[1],就是说长度为1的LIS的最小末尾是2,这时len=1,然后把d[2]有序的放到B里,令B[1]=1(d[2]),就是说长度为1的LIS最小末尾是1,d[1]=2已经没有用了,这是len=1不变。接着d[3]=5,5>1,所以令B[1+1]=d[3]=5,就是说长度为2的LIS的最小末尾是5,此时B[1...2]=1,5,len=2。

再来,d[4]=3,它正好在1和5之间,当然放在1的位置上不合适,因为1<3,因此长度为2的最小末尾应该是3,淘汰掉5,这时候B[1...2]=1,3,len=2,继续d[5]=6,它在3后边,所以B[3]=4,B[1...3]=1,3,6,len=3。

第6个,d[6]=4,它加在3和6之间,所以我们把6换掉,这样B[1...3]=1,3,4,len=3。

第7个,d[7]=8,8>4,所以B[4]=8,B[1...4]=1,3,4,8,len=4。

第8个,d[8]=9,B[1...5]=1,3,4,8,9,len=5。

最后一个,d[9]=7,所以B[1...5]=1,3,4,7,9,len=5。

注意这里的B并不是LIS,而是对应长度的LIS的最小末尾。

现在可以发现B插入数据是有序的,而且进行替换而不需要移动,也就是说可以使用二分查找,时间复杂度就降下来了。

注意了,这种算法只能得到最终的数据个数,但是如果需要得到具体的内容就不行了。

摘自Lce_Crazy的博客

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
const int MAXN = 500000 + 100;
int a[MAXN];
int b[MAXN];
using namespace std;
int main()
{
    int n,left,right,mid;
    while(~scanf("%d",&n))
    {
        memset(b,0,sizeof(b));
        int len = 1;
        for(int i = 1;i <= n;i++)
        {
            scanf("%d",a[i]);
        }
        b[1] = a[1];
        for(int i = 2;i <= n;i++)
        {
            left = 1;
            right = len;
            while(left < right)
            {
                mid = (left + right) / 2;
                if(a[i] >= b[mid])
                    left = mid + 1;
                else
                    right = mid;
            }
            if(b[right] > a[i])
            {
                b[right] = a[i];
            }
            else
                b[++len] = a[i];
        }
        printf("%d\n",len);
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值