最长上升子序列--模板

文章介绍了如何使用动态规划优化求解最长上升子序列问题,包括基本方法、贪心+二分优化以及记录路径的方法,重点讨论了单调栈和二分查找在算法中的应用。
摘要由CSDN通过智能技术生成

例题

动态规划,f[i] 表示 以第 i 个数结尾的最长上升子序列的长度。

n平方级别:
 

#include <iostream>
#include <algorithm>
#include <cstring>

using namespace std;

//表示:  f[i]表示以第i个数	为结尾的最长上升子序列;
//属性:  最大值
//计算;  f[i]=max(f[i],f[j]+1) j<=i;
//初始化
const int N=1010;
int n;
int a[N];
int f[N];

int main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
		cin>>a[i];
	
	for(int i=1;i<=n;i++)
	{
	    f[i]=1;
		for(int j=1;j<=i;j++)
		if(a[i]>a[j])
		f[i]=max(f[i],f[j]+1);
	}
	int res=0;
	for(int i=1;i<=n;i++)
	res=max(res,f[i]);
	cout<<res;
	return 0;
 } 


优化,有三份代码:第一二份是优化了算法,可以利用贪心+二分优化递推的过程。
第三份是记录路径。
 

//思路:单调栈;
//如果  a[i]>stake.back()  直接插入;
//否则,贪心的思想,二分找到第一个大于等于a[i]
//的数进行替换,因为最后一个数最小一定更优;
//但是不能存路径了

//较小的数开头的数作为的子序列 比 较大的数作为开头的子序列 更好

//如样例:
//7
//1 2 8 9 10 5 6
//输出:
//5
//1 2 5 6 10 

#include <bits/stdc++.h>
#define int long long //(有超时风险)
#define PII pair<int,int>
#define endl '\n'
#define LL __int128

using namespace std;

const int N=2e5+10,M=1e3+10,mod=998244353,INF=0x3f3f3f3f;

int a[N],b[N],c[N],pre[N];

signed main()
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);

    int n;cin>>n;
    for(int i=1;i<=n;i++)
        cin>>a[i];

    vector<int>q;
    q.push_back(a[1]);

    for(int i=1;i<=n;i++)
    {
        if(a[i]>q.back())
            q.push_back(a[i]);
        else
        {
            //vector<int>::iterator
            auto k= lower_bound(q.begin(),q.end(),a[i]);
            *k=a[i];
        }
    }
    cout<<q.size()<<endl;

    return 0;
}
#include <bits/stdc++.h>
#define int long long //(有超时风险)
#define PII pair<int,int>
#define endl '\n'
#define LL __int128

using namespace std;

const int N=2e5+10,M=1e3+10,mod=998244353,INF=0x3f3f3f3f;

int cnt=0;
int a[N],f[N];

int check(int x)
{
    int l=1,r=cnt;
    while(l<r)
    {
        int mid=(l+r)/2;
        if(f[mid]>=x)r=mid;
        else l=mid+1;
    }
    return l;
}

signed main()
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);

    int n;cin>>n;
    for(int i=1;i<=n;i++)
        cin>>a[i];

    f[++cnt]=a[1];
    for(int i=1;i<=n;i++)
    {
        if(a[i]>f[cnt])f[++cnt]=a[i];
        else
        {
            int tmp=check(a[i]);
            f[tmp]=a[i];
        }
    }
    cout<<cnt<<endl;
    return 0;
}
//还是可以记录路径的

#include <bits/stdc++.h>
#define int long long //(有超时风险)
#define PII pair<int,int>
#define endl '\n'
#define LL __int128

using namespace std;

const int N=2e5+10,M=1e3+10,mod=998244353,INF=0x3f3f3f3f;

int a[N],b[N],c[N],pre[N],f[N];
string ans[N];
signed main()
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);

    int n;cin>>n;

    for(int i=1;i<=n;i++)
        cin>>a[i];

    int len=0;//表示当前最长上升子序列长度
    //ans[k]表示以k为长度的子序列的最优方案。
    for(int i=1;i<=n;i++)
    {
        auto k= lower_bound(f+1,f+len+1,a[i])-f;
        f[k]=a[i];
        len=max(len,k);
        cout<<f[k]<<endl;
        cout<<a[i]<<' '<<k<<' '<<ans[k]<<endl;
        ans[k]=ans[k-1]+to_string(a[i]);
    }
    cout<<ans[len]<<endl;
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值