最长上升子序列n*n和nlogn 算法

最长上升子序列是常见的DP问题.数组b[1]~b[n]中存放着n个数字,
从1~n都有,顺序不定。
第一种方法是n*n时间复杂度的算法,利用一个数组d[i](i从1到n)存放着以b[i]作为结尾的最长子序列的长度,则状态转换方程为:
d[i]=max(d[j]+1) (b[i]>b[j] ,i>j) 边界是b[1]=1;

int n,b[n+1],d[n+1];//b[n+1]中存放原来的数组,d[n+1]中存放最长上升子序列的长度
int p[n+1];//p[i]中存放着以b[i]作为最长子序列结尾的上一个字符的下标 如果最长子序列就是本身则p[i]=i;
void output(int i)//打印以b[i]结尾的最长子序列
{
    if(p[i]=i)
    {
        cout<<p[i]<<" ";
    }
    else
    {
        output(p[i]);
        cout<<i<<" ";
    }
}
int lis()
{
    for(int i=1;i<=n;i++)
    {
        p[i]=i;//默认每个b[i]都是单独的最长子序列
        d[i]=1;//初始化以b[i]结尾的最长上升子序列长度为1
    for(int i=1;i<=n;i++)
        for(int j=1;j<i;j++)
        {
            if(b[i]>b[j]&&d[i]<d[j]+1)
            {
                d[i]=d[j]+1;
                p[i]=j;
            }
        }
    int maxlength=d[1];
    for(int i=1;i<=n;i++)
        if(maxlength<d[i])
            maxlength=d[i];
    return maxlength;
}

第二种算法的复杂度为nlogn在n很大的情况下可以有效得减少计算的时间,在这种算法中用d[len]存储使得最长上升子序列长度为len的最小的结尾,这里为什么要存储最小的结尾呢,因为只有保证d[len]中存放的是最小的
则下次检查b[i]的时候才最容易更新len使得len++,这样才获得最大的len。
在检测b[i]的时候分两种情况
(1).b[i]>d[len] 则len++;d[len]=b[i]
(2)b[i]<=d[len] 则在1~len直接寻找j 使得d[j-1]

#include <iostream>
#include <sstream>
using namespace std;
const int NMAX=20;
int len;
int b[NMAX+1],d[NMAX+1];
int binary_search(int i)//而非查找大于等于i的最小下标
{
    int left=1,right=len,middle;
    while(left<right)
    {
        middle=left+(right-left)/2;
        if(d[middle]>=i)right=middle;
        else left=middle+1;
    }
    return left;
}
int getscore(int n)
{
    len=1;//len为当前最大上升子序列的长度
    d[1]=b[1];//d[i]中存放的是最长上升子序列长度为i的最小结尾
    for(int i=2;i<=n;i++)
    {
        if(b[i]>d[len])
        {
            len++;//更新最长上升子序列的长度
            d[len]=b[i];//更新最长上升子序列的末尾
        }
        else
        {
            int num=binary_search(b[i]);//求出d[1]~d[len]中>=b[i]的最小值的下标 
            d[num]=b[i];//更新num下标所对应的的最小结尾
        }
    }
    return len;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hebastast

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值