最长上升子序列模板(dp,二分)

普通版本,简单易懂但是时间复杂度高, O ( n 2 ) O(n^2) O(n2),在第一次遍历的同时遍历之前的部分看新出现的元素能否加到之前出现的元素的序列之前。

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
const int N=1e6+7;
const int inf=0x3f3f3f3f;
int a[N],dp[N];
signed main()
{
    int n;
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
    }
    for(int i=1;i<=n;i++)
    {
        dp[i]=1;//将以a[i]结尾的最长上升子序列的长度设为1
        for(int j=1;j<i;j++)
        {
            if(a[i]>a[j])
                dp[i]=max(dp[i],dp[j]+1);//如果a[i]>a[j],说明a[j]可以加到以a[i]结尾的子序列后面
        }
    }
    cout<<*max_element(dp+1,dp+1+n)<<endl;//取最大值
    return 0;
}

用d数组记录长度为len的序列的最优结尾,每次出现一个新元素,就二分遍历该数组寻找新元素能够作为哪个长度的子序列的最优结尾,最后输出d数组大小即可。

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
const int N=1e6+7;
const int inf=0x3f3f3f3f;
int a[N],d[N];
signed main()
{
    int n;
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
    }
    int len=1;d[1]=a[1];
    for(int i=1;i<=n;i++)
    {
        if(a[i]>d[len])//如果a[i]大于目前最长上升子序列的最优结尾,那么长度加一,结尾替换
        {
        	len++;
        	d[len]=a[i];//这里的d[N]数组记录的是长度为len的上升子序列的最优结尾
        }
        else//如果新出现的a[i]小于目前最长上升子序列的最优结尾
        {
        	d[lower_bound(d+1,d+len+1,a[i])-d]=a[i];//二分查找将该结尾放到最优的位置,替换掉前面比他大的最优结尾,成为最优结尾
		}
    }
    cout<<len<<endl;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值