目录

个人介绍

子序列的定义

上升子序列的定义

阎氏dp分析法

状态表示

属性

状态计算

初始化

代码模板

最长上升子序列的变形1:

例题1:

分析:

代码:

例题二:

分析:

代码:

总结:

最长上升子序列的变形2:

例题:最大上升子序和

分析:

代码:

最长上升子序列的变形3:

例题:

分析:

代码:


个人介绍

各位CSDN的友友们,大家好,我是小熙,一个算法小透明,希望在CSDN的大舞台可以和大家一起取得进步(^_^)

个人现状:上个学期在学校的ACM小组学了一个学期的算法,但是世界很大,我的梦想很远,我希望在我年轻的时候可以走出国门,到世界的其他地方看一看,再加上我的算法功底可能真的不太足以支持我在ACM比赛上做出成绩。所以我选择逐渐淡出ACM小组,并把之前的知识整理成博客供大家分享。

学习算法的小方法:知道算法的基本原理——>知道代码实现——>总结出代码模板并熟练于心——>基本模板题——>变式思维题

子序列的定义

子序列指的是去掉原数列中的任意位置的元素若干次,且不改变其先后顺序,得到的新数列。比如下图数列中“2 3 8 0”可以看做是一个子序列,“7,8”也可以看做是一个子序列。

上升子序列的定义

顾名思义,如果一个数列的子序列中元素大小是单调递增的,那么这个子序列就是上升子序列。如下图的“2 3 8 0”就不是,“7,8”就是

阎氏dp分析法

状态表示

dp[i]:表示数列中以第i个数据结尾的最长上升序列的长度。(这里就要注意了,我们线性dp设置状态的时候经常以集合中的最后一个元素进行状态的划分)

属性

通常属性有max/min/数量。这里最长上升子序列明显就是max。

状态计算

就以下图为例,i,j表示的是数组中元素的下标,i表示的是当前元素的下标,j表示的是i之前的元素的下标。

初始化

把dp[i]中的每一个元素的dp[i]设置为1

代码模板

这个专题的模板我们以题目的形式来呈现

#include<bits/stdc++.h>
using namespace std;
const int N=1e3+10;
int n;
int a[N];
int dp[N];
int main()
{cin>>n;for(int i=1;i<=n;i++) cin>>a[i];for(int i=1;i<=n;i++) dp[i]=1;//初始化for(int i=2;i<=n;i++){for(int j=1;j<i;j++){if(a[i]>a[j]){dp[i]=max(dp[i],dp[j]+1);//dp的状态计算}}}int res=0;for(int i=1;i<=n;i++) res=max(res,dp[i]);cout<<res<<endl;return 0;
}

最长上升子序列的变形1:

例题1:

【题目描述】
怪盗基德是一个充满传奇色彩的怪盗,专门以珠宝为目标的超级盗窃犯。而他最为突出的地方,就是他每次都能逃脱中村警部的重重围堵,而这也很大程度上是多亏了他随身携带的便于操作的滑翔翼。

有一天,怪盗基德像往常一样偷走了一颗珍贵的钻石,不料却被柯南小朋友识破了伪装,而他的滑翔翼的动力装置也被柯南踢出的足球破坏了。不得已,怪盗基德只能操作受损的滑翔翼逃脱。

假设城市中一共有N幢建筑排成一条线,每幢建筑的高度各不相同。初始时,怪盗基德可以在任何一幢建筑的顶端。他可以选择一个方向逃跑,但是不能中途改变方向(因为中森警部会在后面追击)。因为滑翔翼动力装置受损,他只能往下滑行(即:只能从较高的建筑滑翔到较低的建筑)。他希望尽可能多地经过不同建筑的顶部,这样可以减缓下降时的冲击力,减少受伤的可能性。请问,他最多可以经过多少幢不同建筑的顶部(包含初始时的建筑)?

【输入】
输入数据第一行是一个整数K(K<100),代表有K组测试数据。

每组测试数据包含两行:第一行是一个整数N(N<100),代表有N幢建筑。第二行包含N个不同的整数,每一个对应一幢建筑的高度h(0<h<10000),按照建筑的排列顺序给出。

【输出】
对于每一组测试数据,输出一行,包含一个整数,代表怪盗基德最多可以经过的建筑数量。

【输入样例】
3
8
300 207 155 299 298 170 158 65
8
65 158 170 298 299 155 207 300
10
2 1 3 4 5 6 7 8 9 10

【输出样例】
6
6
9

分析:

有没有看着一年懵圈,这和最长上升子序列有什么关系,实际上这题的本质是让我们求取从数组左边以起点开始到对应点的最长上升子序列dp1[1]和以数组右边为起点开始到对应点的最长上升子序列dp2[i]。

代码:

#include<bits/stdc++.h>
using namespace std;
int k,n;
const int N=1e5+10;
int a[N];
int dp1[N];//表示以左边为起点的最长上升子序列的dp的值
int dp2[N];//表示以右边为起点的最长上升子序列的dp的值
int main()
{cin>>k;while(k--){cin>>n;for(int i=1;i<=n;i++) dp1[i]=1;for(int i=1;i<=n;i++) dp2[i]=1;for(int i=1;i<=n;i++) a[i]=0;for(int i=1;i<=n;i++) cin>>a[i];for(int i=2;i<=n;i++){for(int j=1;j<i;j++){if(a[i]>a[j]) dp1[i]=max(dp1[i],dp1[j]+1);//dp的是以左边为起点的最长上升子序列的值}}for(int i=n;i>=1;i--){for(int j=n;j>i;j--){if(a[i]>a[j]) dp2[i]=max(dp2[i],dp2[j]+1);//dp的是以左边为起点的最长上升子序列的值}}int res=0;for(int i=1;i<=n;i++) res=max(res,max(dp1[i],dp2[i]));cout<<res<<endl;//计算结果}
}

例题2:

分析:

(1):看到“不连续游览海拔相同的两个景点”,“一旦开始下山,就不往上走”就应该要联想到下图这张“山峰型”的图

(2)不难看出,答案就是max(dp1[i]+dp2[i])[1<=i<=n]

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=1e3+10;
int a[N];
int dp1[N];
int dp2[N];
int n;
int main()
{cin>>n;for(int i=1;i<=n;i++) cin>>a[i];for(int i=1;i<=n;i++) dp1[i]=1;for(int i=1;i<=n;i++) dp2[i]=1;for(int i=1;i<=n;i++){for(int j=1;j<i;j++){if(a[i]>a[j]) dp1[i]=max(dp1[i],dp1[j]+1);}}for(int i=n;i>=1;i--){for(int j=n;i<j;j--){if(a[i]>a[j]) dp2[i]=max(dp2[i],dp2[j]+1);}}int res=0;for(int i=1;i<=n;i++) res=max(res,dp1[i]+dp2[i]);cout<<res-1<<endl;//要减去一,因为当前的点被重复计算了两次return 0;
}

总结:

(1):关于最长单调子序列延伸出来的山峰模型

凡是题干中有要求答案先升后降的趋势,就要想到这个点,上面的两道题都有这个特点。

最长上升子序列的变形2:

例题:最大上升子序和

分析:

(1):之前讲了,线性dp经常以集合中的最后一个元素进行转态的划分 ,这里dp[i]表示的就是以第i个元素为结尾的最大上升子序列的值。

(2):只要满足递增的条件,dp[i]=max(dp[i],dp[j]+a[i])

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=1e3+10;
int a[N];
int n;
int dp[N];
int main()
{cin>>n;for(int i=1;i<=n;i++) cin>>a[i];for(int i=1;i<=n;i++) dp[i]=a[i];for(int i=1;i<=n;i++){for(int j=1;j<i;j++){if(a[i]>a[j]) dp[i]=max(dp[i],dp[j]+a[i]);}}int res=0;for(int i=1;i<=n;i++) res=max(res,dp[i]);cout<<res;return 0;
}

最长上升子序列的变形3:

例题:

P2782 友好城市 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

分析:

刚开始看的时候有些慌张,但是在纸上一模拟发现就是最长上升子序列的问题。

(1):每个城市是一一映射的函数关系,那么我们不妨开一个pair数组然后按照第一个城市编号的大小排序,这样第一个城市的编号就不用管了,理解为数组的下标就可以了,第二个城市就理解为数组的值就行了,然后套用最长上升子序列的模板。

代码:

#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> pii;//数据类型
const int N=2e5+10;
pii a[N];//开pair类型的数组,呵呵,有点意思
int dp[N];
int main()
{int n;cin>>n;for(int i=1;i<=n;i++){cin>>a[i].first>>a[i].second;}sort(a+1,a+1+n);//如果a数组是pair类型就按照pair数组的第一个数据的大小排序for(int i=1;i<=n;i++) dp[i]=1;for(int i=1;i<=n;i++){for(int j=1;j<i;j++) {if(a[i].second>a[j].second) dp[i]=max(dp[i],dp[j]+1);}}int res=0;for(int i=1;i<=n;i++) res=max(res,dp[i]);cout<<res;
}

手撕大厂笔试之最长上升子序列和它的各种变式相关推荐

  1. 华为面试手撕真题【最长不重复子串】

    给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度. 一道leetcode原题:力扣 虽然是一个原题,但是面试官可能会出一个不同的变种,就是不输出最长的长度,而是输出最长子串的字符串 ...

  2. Interview:算法岗位面试—11.06早上上海某智能驾驶科技公司(创业)笔试+面试之手撕代码、项目考察、比赛考察、图像算法的考察等

    Interview:算法岗位面试-11.06早上上海某智能驾驶科技公司(创业)笔试+面试之手撕代码.项目考察.比赛考察.图像算法的考察等 导读:该公司是在同济某次大型招聘会上投的,当时和HR聊了半个多 ...

  3. 数字IC手撕代码-兆易创新笔试真题

    前言: 本专栏旨在记录高频笔面试手撕代码题,以备数字前端秋招,本专栏所有文章提供原理分析.代码及波形,所有代码均经过本人验证. 目录如下: 1.数字IC手撕代码-分频器(任意偶数分频) 2.数字IC手 ...

  4. 【2023校招刷题】笔试及面试中常考知识点、手撕代码总结

    文章目录 一.笔试/面试常考知识点 二.面试常考手撕代码 2.1.基本电路设计 2.2.复杂电路设计 2.3.跨时钟域设计 一.笔试/面试常考知识点 奇.偶.小数分频 [Verilog基础]分频器实现 ...

  5. 数字IC手撕代码-乐鑫科技笔试真题(4倍频)

    前言: 本专栏旨在记录高频笔面试手撕代码题,以备数字前端秋招,本专栏所有文章提供原理分析.代码及波形,所有代码均经过本人验证. 目录如下: 1.数字IC手撕代码-分频器(任意偶数分频) 2.数字IC手 ...

  6. C/C++笔试面试手撕代码注意事项

    C/C++笔试和面试过程中难免会要手撕代码,那么手撕代码,面试官或者看试卷的人一般会看哪些点呢?我列举了一些我认为的点(码农适用): 算法思想是否正确 代码逻辑是否清晰明了 代码风格是否美观简洁 注释 ...

  7. 数字IC手撕代码-泰凌微笔试真题

    前言: 本专栏旨在记录高频笔面试手撕代码题,以备数字前端秋招,本专栏所有文章提供原理分析.代码及波形,所有代码均经过本人验证. 目录如下: 1.数字IC手撕代码-分频器(任意偶数分频) 2.数字IC手 ...

  8. 一看“左程云:200道算法与数据结构”,二刷“阿里云:70+算法题、30种大厂笔试高频知识点”,3月过去终于挺进我梦中的字节!

    不管是学生还是已经工作的人,我想彼此都有一个相同的梦想:进大厂! 眼看着2020年还有个三十来天就要完美收尾了,那么如何才能在未来三个月弯道超车赶上"金三银四的春招",进入梦寐以求 ...

  9. 数字IC手撕代码-流水握手(利用握手解决流水线断流、反压问题)

    前言: 本专栏旨在记录高频笔面试手撕代码题,以备数字前端秋招,本专栏所有文章提供原理分析.代码及波形,所有代码均经过本人验证. 目录如下: 1.数字IC手撕代码-分频器(任意偶数分频) 2.数字IC手 ...

最新文章

  1. windows 7使用CAJViewer时出错显示缺少ReaderEX.dll处理
  2. 调用父级方法_通信:找到任意组件实例的findComponents系列方法,5个终极方案
  3. vs2013+EF6+Mysql
  4. XML文档注释(C#)
  5. spring框架(三)mvc
  6. 为什么太重感情的人基本都是穷人?
  7. Linux命令解释之cp
  8. Dato for Mac(菜单栏时钟工具)支持m1
  9. 内存分配——栈、堆、静态区、符号区等等
  10. php图书馆占座系统代码,基于php的图书馆座位管理系统
  11. USB 协议整理 二:USB概述及协议基础(一)
  12. 简单粗暴理解与实现机器学习之聚类算法(四):模型评估、误差平方和SSE、“肘”方法 、轮廓系数法、CH系数
  13. 移动应用众包测试综述
  14. 截图或者模糊图片高清处理方式
  15. python工具类-sql操作封装
  16. 51单片机用c语言倒计时程序,51单片机实现100以内倒计时,求大佬指点。
  17. bilibili注册页面编码HTML码,哔哩哔哩bilibili新人邀请码在哪填写 B站怎么绑定输入邀请码方法...
  18. Linux-Ubuntu 和 安装 genymotion 的一些问题和一些命令
  19. docker网络模式与none模式配置网络
  20. class与Class的区别

热门文章

  1. 2022加氢工艺题库及模拟考试
  2. Unity3D直线绘制
  3. linux中ftp怎么进不去,FTP进不去怎么办?FTP老进不去解决方法
  4. python算法二:迭代法
  5. Android U盘不可写
  6. 如何将iphone手机里的照片视频批量传到 Mac
  7. 一块金胜维128G M.2 NGFF SSD固态硬盘量产开卡恢复过程分享+INIC-6081开卡软件和PS3111量产工具下载
  8. 写给自己的2016年总结
  9. 本周(10.29-11.2)热门岗位|互联网
  10. Varnish安装部署文档