C++最长上升子序列

C++最长上升子序列现有数列a1,a2,a3……aN。在其中找到严格递增序列ai1,ai2,ai3,……aiK(1<=i1

大家好,又见面了,我是你们的朋友全栈君。

最长上升子序列简介

题目描述
现有数列a1,a2,a3……aN。在其中找到严格递增序列ai1,ai2,ai3,……aiK(1 <= i1 < i2 < i3 < …… < iK <= N),请找出序列a的最长上升子序列的长度,既K的最大值。

输入格式
第一行:一个整数N。
第二行:N个整数a1,a2,a3……aN。

输出格式
一行,最大的K。

输入样例

10
5 10 8 9 7 10 13 12 25 13

输出样例

6

二维动态规划解法

提到DP,就一定就要去想:状态、转移方程、初值和答案了。

  1. 状态:dp[i]指在1~i这i个数中,必须包含a[i]这个数的最长上升子序列。
  2. 转移方程:if(a[j] < a[i]) dp[i] = max(dp[i], dp[j] + 1)(1 <= j <= i – 1)
    其实这个的意思就是:如果说在1~(i – 1)这(i – 1)个数中,a[j] < a[i],a[i]就可以接上a[j],形成一个比dp[j]又多了1的递增序列,因此每次判断并取最大值就行了。
  3. 初值:dp[i] = 1(一个数本身就是一个递增序列)。
  4. 答案:max{dp[i]}

(PS:NR指序列长度的上限)

# include <cstdio>
# include <iostream> 
# include <cmath>
# include <cstring>
# include <algorithm>

using namespace std;

# define FOR(i, a, b) for(int i = a; i <= b; i++)
# define _FOR(i, a, b) for(int i = a; i >= b; i--)

const int NR = 100000;

int n, ans;
int a[NR + 2], dp[NR + 2];

int main()
{ 
   
    scanf("%d", &n);
    FOR(i, 1, n) scanf("%d", &a[i]);
    FOR(i, 1, n) dp[i] = 1;
    FOR(i, 2, n){ 
   
        FOR(j, 1, i - 1)
            if(a[j] < a[i]) dp[i] = max(dp[i], dp[j] + 1);
        ans = max(ans, dp[i]);
    }
    printf("%d\n", ans);
    return 0;
}

贪心二分查找解法

二维动态规划的时间复杂度为On^2,太多了,我们想去优化,可是我们发现直接在二维上改好像改不了,没办法,只好再想一个新的方法了。

这次,我们开一个新的数组f,f[i]表示当上升子序列长度为i时,此子序列最后一个元素的最小值。我们会发现这个f数组是随着i值的增加,f[i]不断增大的单调队列。因为如果长度为i的上升子序列最后一位都为f[i]了,那长度(i + 1)的最后一位至少也得是f[i] + 1了吧。

这样我们从1到n一个元素一个元素的分析,当到了第i个元素时,我们在f数组中找第一个大于等于a[i]的f[k],这就代表长度为(k – 1)的上升子序列最后一位的最少值是f数组中最后一个小于a[i]的数,所以就让我们就可以把a[i]放到长度为(k – 1)的这个上升子序列的后面,形成一个新的长度为k的这个上升子序列,接下来更新f[k]的值f[k] = min(f[k], a[i])可我们发现我们找f[k]时就说了f[k]是f数组中第一个大于等于a[i]的数,所以直接f[k] = a[i]就好了。

下图仅供参考。
在这里插入图片描述
其中,在f数组中找第一个大于等于a[i]的f[k]时,可以用到二分查找函数中的lower_bound函数。

如果你还没有学过lower_bound可以到此网站学习lower_bound函数的用法
https://blog.csdn.net/SkeletonKing233/article/details/99479707

这样时间复杂度就从On^2降到了Onlogn,大大减少了时间的消耗。

以下为代码:

# include <cstdio>
# include <iostream> 
# include <cmath>
# include <cstring>
# include <algorithm>

using namespace std;

# define FOR(i, a, b) for(int i = a; i <= b; i++)
# define _FOR(i, a, b) for(int i = a; i >= b; i--)

const int NR = 100000;

int n, ans;
int a[NR + 2];
int f[NR + 2];

int main()
{ 
   
	scanf("%d", &n);
 	FOR(i, 1, n) scanf("%d", &a[i]);
 	f[0] = -2e9;
 	FOR(i, 1, n){ 
   
 		int k = lower_bound(f, f + ans + 1, a[i]) - f;
 		f[k] = a[i];
 		ans = max(ans, k);
	}
	printf("%d\n", ans);
	return 0;
}

最长下降、不上升、不下降子序列

剩下的这三种都与第一种十分相像:

  • 最长不下降子序列:就是把FOR循环中的lower_bound函数改成upper_bound函数。
  • 最长下降子序列:就是把FOR循环前的f[0] = -2e9改成f[0] = 2e9之后再在全局写一个比较函数cmp,并在lower_bound函数中做为第4个参数引用
  • 最长不上升子序列:就是先改成最长下降子序列,之后再把FOR循环中的lower_bound函数改成upper_bound函数。

PS:cmp函数的写法:

bool cmp(int x, int y){ 
   
	return x > y;
}
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/131509.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • IMDb Top 250佳片榜_吹哨人 电影

    IMDb Top 250佳片榜_吹哨人 电影互联网电影资料库(英语:InternetMovieDatabase,简称IMDb)是一个关于电影演员、电影、电视节目、电视艺人、电子游戏和电影制作小组的在线数据库。IMDb开办于1990年10月17日,从1998年开始成为亚马逊公司旗下的网站,在2010年10月17日时,IMDb庆祝了他们20周年的纪念。用户评分最高的250部电影进入Top250榜单,但并非简单地根据平均分值来排名,而…

    2022年9月23日
    3
  • php 清楚浏览器缓存,如何清除浏览器缓存「建议收藏」

    php 清楚浏览器缓存,如何清除浏览器缓存「建议收藏」头像是根据url指定的,更改头像后url仍然不变,即url指向的图片地址没变,但图片已经更换了因为url没变所以浏览器还是用原来的图片,怎么更改后及时显示新的图片呢?是因为浏览器的缓存吗,怎么用php清楚浏览器缓存呢回复内容:头像是根据url指定的,更改头像后url仍然不变,即url指向的图片地址没变,但图片已经更换了因为url没变所以浏览器还是用原来的图片,怎么更改后及时显示新的图片呢?是因为浏…

    2022年7月18日
    21
  • layui实现数据分页功能_layui分页使用

    layui实现数据分页功能_layui分页使用最近需要对后台的数据进行分页渲染并且需要进行表头动态渲染,因此和小伙伴一起学习了layui的数据表格渲染,然后进行了改进,成功之后记录了下来先说前端HTML和js代码先下载layuijs文件,在页面引入layui的js在HTMLboday标签中添加table容器,id为demo $(function(){ getData(); }) functiongetData(){

    2025年8月1日
    4
  • 程序员外包平台_人力资源外包和劳务派遣

    程序员外包平台_人力资源外包和劳务派遣程序员接单平台,程序员接单,程序员外包平台,程序员外包

    2022年9月29日
    3
  • Jenkins配置-Invoke ant

    一般的配置在这里就不多说了。如果要执行某个xml文件里的某个target该怎么配置呢如下图

    2022年4月9日
    165
  • 信息录入系统_资料管理系统

    信息录入系统_资料管理系统123231newVue({2el:'#app',3mounted(){4this.getStudentList();5},6data:{7s

    2022年8月2日
    9

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号