最长下降子序列

文章目录

  • 题目
  • 解法
    • DP+暴搜
      • 思路
      • 代码实现
    • 贪心+二分
      • 思路
      • 代码实现


题目

给出一组数据 nums,求出其最长下降子序列(子序列允许不连续)的长度。(类似于lc的最长递增子序列)

示例:

输入:

6 // 数组元素个数
3 4 3 5 2 1 // 数组

输出:

4 // 最长下降子序列为4321,长度为4

解法

DP+暴搜

思路

DP数组 表示 nums数组 对应下标的元素作为末尾时最长下降子序列的长度,因此将 DP数组中的元素 全部初始化为 1(最起码这个下降子序列里有当前元素)。

nums第二个元素开始(记为 i),向前搜索所有大于它的元素(记为 j),找到后 dp[i] = max(dp[i], dp[j] + 1) 。举个例子会更直观:

nums = 3 4 3 5 2 1
dp =   1 1 2 1 3 4⬆形成下降子序列:4,3   

i=4, nums[i]=2 时,这个状态转移方程显得尤为重要:

  • j=0 开始遍历,第一个大于 2 的元素是 j=1, nums[j]=4dp[i]=dp[j]+1=2,意味着可以形成下降子序列:4,2,长度为 dp[i]=2
  • 第二个大于 2 的元素是 j=2, nums[j]=3dp[i]=dp[j]+1=3,意味着可以形成下降子序列:4,3,2
  • 第三个大于 2 的元素是 j=3, nums[j]=5dp[i]=dp[i]=3,意味着形成 5,2 不如形成 4,3,2 更长,所以仍保持原来的下降子序列。

值得注意的是最长下降子序列的长度是 DP数组 中最大的元素而非尾元素,举个例子:

nums = 3 4 3 5 2 3
dp =   1 1 2 1 3 2

因此在构建 DP数组 的同时要记得保存最大元素哦~

代码实现

int main() {int n, res = 1;cin >> n;vector<int> v(n), dp(n, 1);for (int i = 0; i < n; i++) {cin >> v[i];}for (int i = 1; i < n; i++) {for (int j = 0; j < i; j++) {if (v[j] > v[i]) dp[i] = max(dp[j] + 1, dp[i]);}res = max(dp[i], res);}cout << res << endl;
}

在这里插入图片描述


贪心+二分

思路

dp数组: 用来暂存一个 下降子序列,注意,这里的序列并非真正的最长下降子序列,至于原因下文解释。由于题目要求的是最长下降子序列的长度,并不用返回序列的具体排列,因此dp数组的长度就是本题的答案

该方法思路分三步:请客、斩首、收下当狗。

  1. 请客:遍历 数据数组 中每个元素,和 dp数组 的尾元素比较。
  2. 收下当狗:如果比较结果是当前遍历到的元素小于 dp数组 尾元素,则当前元素直接加入 dp数组,成为新的尾元素
  3. 斩首:斩 dp数组旧元素的首,当前遍历到的元素作为新元素,自然要先收下当狗,具体做法是:
    • 通过二分法找到 dp数组 中所有小于当前元素中最大的那个,用当前元素替换掉它。举个例子,比如:dp数组元素是 9,5,3,1。当前遍历到的元素是 6,那么dp数组会变成:9,6,3,1

为什么说 dp数组 暂存的下降子序列只是和真正的最长下降子序列长度相等,两者内容并不一样?

原因就在于第3点——斩首,斩首的目的是 在不改变子序列长度的基础上扩大下降子序列的最小值,用具体例子来说明:

假如给出的数据是 3,4,3,5,2,1。那么 dp数组 的变化会是:

dp数组内容当前遍历到的元素最长下降子序列 |
333
444 或 3
4,334,3
5,354,3
5,3,224,3,2
5,3,2,114,3,2,1

代码实现

int main() {int n;cin >> n;vector<int> v(n), dp;for (int i = 0; i < n; i++) {cin >> v[i];}dp.push_back(v[0]);for (int i = 1; i < n; i++) {if (v[i] < dp.back()) dp.push_back(v[i]);else {int l = 0, r = dp.size()-1;while (l < r) {int m = l + (r - l) / 2;if (v[i] < dp[m])l = m + 1;else r = m;}dp[l] = v[i];}for (int j : dp) {cout << j << " ";}cout << endl;}cout << dp.size() << endl;
}

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/443725.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux 服务器程序规范、服务器日志、用户、进程间的关系

文章目录服务器程序规范日志rsyslogd 守护进程syslog函数openlog函数setlogmask函数closelog函数用户进程间的关系进程组会话系统资源限制改变工作目录和根目录服务器程序后台化服务器程序规范 Linux 服务器程序一般以后台进程&#xff08;守护进程[daemon]&#xff09;形式运…

IO模型 :阻塞IO、非阻塞IO、信号驱动IO、异步IO、多路复用IO

文章目录IO模型阻塞IO非阻塞IO信号驱动IO多路复用IO异步IOIO模型 根据各自的特性不同&#xff0c;IO模型被分为阻塞IO、非阻塞IO、信号驱动IO、异步IO、多路复用IO五类。 最主要的两个区别就是阻塞与非阻塞&#xff0c;同步与异步。 阻塞与非阻塞 阻塞与非阻塞最主要的区别就…

Tomcat服务器集群与负载均衡实现

一、前言 在单一的服务器上执行WEB应用程序有一些重大的问题&#xff0c;当网站成功建成并开始接受大量请求时&#xff0c;单一服务器终究无法满足需要处理的负荷量&#xff0c;所以就有点显得有点力不从心了。另外一个常见的问题是会产生单点故障&#xff0c;如果该服务器坏掉…

Linux服务器 | 事件处理模式:Reactor模式、Proactor模式

文章目录Reactor模式Proactor模式同步I/O模型模拟Proactor模式两者的优缺点ReactorProactor同步I/O模型通常用于实现 Reactor 模式&#xff0c;异步I/O模型通常用于实现 Proactor 模式。&#xff08;不是绝对的&#xff0c;同步I/O也可模拟出 Proactor 模式&#xff09; React…

Linux服务器 | 服务器模型与三个模块、两种并发模式:半同步/半异步、领导者/追随者

文章目录两种服务器模型及三个模块C/S模型P2P模型I/O处理单元、逻辑单元、存储单元并发同步与异步半同步/半异步模式变体&#xff1a;半同步/半反应堆模式改进&#xff1a;高效的半同步/半异步模式领导者/追随者模式组件 &#xff1a;句柄集、线程集、事件处理器工作流程两种服…

字符串匹配之KMP(KnuthMorrisPratt)算法(图解)

文章目录最长相等前后缀next数组概念代码实现图解GetNext中的回溯改进代码实现代码复杂度分析最长相等前后缀 给出一个字符串 ababa 前缀集合&#xff1a;{a, ab, aba, abab} 后缀集合&#xff1a;{a, ba, aba, baba} 相等前后缀 即上面用同样颜色标识出来的集合元素&#…

Android入门(一) | Android Studio的配置与使用

文章目录安装配置Android Studio使用Android Studio模拟器更改Android SDK的路径Hello World&#xff01;安装配置Android Studio 从这一步开始&#xff1a; 一直点 next 即可&#xff0c;直到存储路径的选择上&#xff0c;可以放到非 C 盘&#xff0c;这里我放到 D 盘了&am…

Android 入门(四) | Intent 实现 Activity 切换

文章目录Intent显式 Intent定义两个 xml 文件android:orientationmatch_parent 和 wrap_contentIntent函数定义两个 Activity隐式 Intent更多隐式 Intent 的用法用隐式 Intent 打开系统浏览器自建 Activity 以响应打开网页的 Intent向下一个活动传递数据返回数据给上一个活动In…

Android入门(二) | 项目目录及主要文件作用分析

文章目录项目目录分析app目录分析AndroidManifest.xml 分析MainActivity.kt 分析build.gradle 分析最外层目录下的 build.gradleapp 目录下的 build.gradle项目目录分析 我们来看一下 src/main/res 下的一些文件&#xff1a; .gradle 和 .idea &#xff1a;这两个目录下放置…

Android入门(三) | Android 的日志工具 Logcat

文章目录日志工具类 android.util.LogLogcat 中的过滤器日志工具类 android.util.Log Log 从属日志工具类 android.util.Log &#xff0c;该类提供了五个方法供我们打印日志&#xff1a; Log.v() &#xff1a;用于打印那些最为琐碎的、意义最小的日志信息。对应级别 verbose&…

Android入门(五) | Activity 的生命周期

文章目录Activity 的状态及生命周期实现管理生命周期FirstActivitySecondActivityDialogActivity运行结果旧活动被回收了还能返回吗&#xff1f;Activity 的状态及生命周期 Android 的应用程序运用 栈&#xff08;Back Stack&#xff09; 的思想来管理 Activity&#xff1a; …

Android入门(六) | Activity 的启动模式 及 生产环境中关于 Activity 的小技巧

文章目录Activity 的启动模式standardsingleTopsingleTasksingleInstance技巧了解当前界面是哪个 Activity随时随地退出程序启动活动的最佳写法Activity 的启动模式 standard&#xff1a;默认的启动方式&#xff0c;每次启动一个活动都会重新创建singleTop&#xff1a;如果该活…

Android入门(七) | 常用控件

文章目录TextView 控件&#xff1a;文本信息Button 控件&#xff1a;按钮EditText 控件&#xff1a;输入框ImageView 控件&#xff1a;图片ProgressBar 控件&#xff1a;进度条AlertDialog 控件&#xff1a;提示框ProgressDialog 控件&#xff1a;带有进度条的提示框TextView 控…

Android入门(八) | 常用的界面布局 及 自定义控件

文章目录LinearLayout &#xff1a;线性布局android:layout_gravity &#xff1a;控件的对齐方式android:layout_weight&#xff1a;权重RelativeLayout &#xff1a;相对布局相对于父布局进行定位相对于控件进行定位边缘对齐FrameLayout &#xff1a;帧布局Percent &#xff1…

Android入门(九)| 滚动控件 ListView 与 RecyclerView

文章目录ListView内置类型的简单运用定制数据类型提升效率点击事件RecyclerView布局管理器点击事件ListView 内置类型的简单运用 由于手机屏幕空间有限&#xff0c;能够一次性在屏幕上显示的内容不多&#xff0c;当我们的程序有大量数据需要显示的时候就可以借助 ListView 来…

Android入门(10)| Fragment碎片详解

文章目录为什么要使用碎片&#xff08;Fragment&#xff09;实例布局文件FragmentActivity动态添加碎片布局文件FragmentActivity碎片通信Fragment布局文件Activity生命周期为什么要使用碎片&#xff08;Fragment&#xff09; 我们在手机上看新闻可能是这样的&#xff1a; Re…

Android开发(1) | Fragment 的应用——新闻应用

文章目录Item&#xff1a;标题子项布局文件Java代码标题碎片布局文件Java代码新闻内容碎片布局文件Java代码新闻内容活动布局文件Java代码首界面布局文件Java代码Item&#xff1a;标题子项 布局文件 news_item.xml&#xff1a; <TextViewxmlns:android"http://schema…

Android入门(11)| 全局广播与本地广播

文章目录广播概念接收广播动态注册实例静态注册实例发送广播发送标准广播广播的跨进程特性发送有序广播本地广播广播概念 Android 中的每个应用程序都可以对自己感兴趣的广播进行注册&#xff0c;这样该程序就只会接收到自己所关心的广播内容&#xff0c;这些广播可能是来自系…

Android开发(2) | 广播 Broadcast 的应用——强制下线功能

文章目录功能简介关闭所有活动登陆界面发送强制下线的广播广播接收器AndroidManifest.xml运行结果功能简介 强制下线功能只需要弹出一个对话框&#xff0c;让用户只能点击确定按钮&#xff0c;回到登录界面。 如果在每一个活动中添加一个对话框的话太过繁琐&#xff0c;用广播…

Android入门(12)| 数据持久化

文章目录数据持久化文件存储将数据存储进文件实例从文件中读取数据实例SharedPreferences存储将数据存储进文件实例从文件中读取数据实例实现记住密码的功能SQLite数据库存储创建自己的帮助类调用自己的帮助类补全 onUpgrade() 方法增删查改增&#xff1a;SQLiteDatabase.inser…