最长上升子序列(LIS)的求法

11 篇文章 0 订阅

最长上升子序列(LIS)
给定一个长度为N的序列A
满足:
1. 1<=x1< x2< x3<…xk<=N
2. A[x1] < A[x2] < A[x3] < … < A[xk]
即寻找一个最长子序列,满足该子序列中每个元素严格递增(其实不严格递增也可以做)
做最长上升子序列有两种方法:

1.动态规划(O(n2))

dp[i]表示取到第i个数的最长上升子序列
若有j满足a[j] < a[i]
dp[i]=max(dp[j])+1
否则dp[i]=1
直接贴代码

#include<cstdio>
long long n,a[10001],dp[10001],ans=0;
int main()
{
    scanf("%lld",&n);
    for(int i=1;i<=n;i++)
        scanf("%lld",&a[i]);
    for(int i=1;i<=n;i++)
    {
        dp[i]=1;
        for(int j=1;j<i;j++)
            if(a[j]<a[i]&&dp[i]<=dp[j])
                dp[i]=dp[j]+1;
    }
    for(int i=1;i<=n;i++)
        if(ans<dp[i])
            ans=dp[i];
    printf("%lld",ans);
    return 0;
}
2.贪心?(O(nlogn))

用一个栈维护最长上升子序列的第i个元素的最小值,显然这个最小值是单调不减的,进来一个数,如果比栈顶打就压入栈,否则二分更新栈内元素
易懂代码

#include<cstdio> 
long long N,a[100001],len,num;
long long search(long long x)
{
    long long l=1,r=len,ans=0;
    while(l<=r)
    {
        long long mid=(l+r)/2;
        if(a[mid]>=x)ans=mid,r=mid-1;
        else l=mid+1;
    }
    return ans;
}
int main()
{
    scanf("%lld",&N);
    for(long long i=1;i<=N;i++)
    {
        scanf("%lld",&num);
        if(len==0||num>a[len])a[++len]=num;
        else a[search(num)]=num;
    }
    printf("%lld",len);
    return 0;
}

经过优化的代码,适合做板子(注意理解)

#include<cstdio>
typedef long long LL;
template <typename T> inline T max(const T a,const T b){return a>b?a:b;}
template <typename T> inline T min(const T a,const T b){return a<b?a:b;}
template <typename T> inline T abs(const T a){return a>0?a:-a;}
template <typename T> inline void swap(T&a,T&b){T c=a;a=b;b=c;}
template <typename T> inline LL log2(T x){register LL res=0;while(x>=2)x=x>>1,res++;return res;}
template <typename T> inline T gcd(const T a,const T b){if(a%b==0)return b;return gcd(b,a%b);}
template <typename T> inline void read(T&x)
{
    char cu=getchar();x=0;bool fla=0;
    while(cu<'0'||cu>'9'){if(cu=='-')fla=1;cu=getchar();}
    while('0'<=cu&&cu<='9')x=x*10+cu-'0',cu=getchar();
    if(fla)x=-x; 
}
template <typename T> void printe(const T x)
{
    if(x>=10)printe(x/10);
    putchar(x%10+'0');
}
template <typename T> inline void print(const T x)
{
    if(x<0)putchar('-'),printe(-x);
    else printe(x);
}
LL N,a[100001],len,num;
inline LL search(const LL x)
{
    register LL l=1,r=len,ans=0;
    while(l<=r)
    {
        register LL mid=(l+r)>>1;
        if(a[mid]>=x)ans=mid,r=mid-1;
        else l=mid+1;
    }
    return ans;
} 
int main()
{
    read(N);
    for(register LL i=1;i<=N;i++)
    {
        read(num);
        if(!len||num>a[len])a[++len]=num;
        else a[search(num)]=num;
    }
    print(len);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值