当前位置: 首页 > news >正文

算法:最长递增子序列

题目

给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。

子序列 是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列
示例 1:

输入:nums = [10,9,2,5,3,7,101,18]
输出:4
解释:最长递增子序列是 [2,3,7,101],因此长度为 4 。
示例 2:

输入:nums = [0,1,0,3,2,3]
输出:4
示例 3:

输入:nums = [7,7,7,7,7,7,7]
输出:1

提示:

1 <= nums.length <= 2500
-104 <= nums[i] <= 104

进阶:

你能将算法的时间复杂度降低到 O(n log(n)) 吗?

问题分析

最长递增子序列(Longest Increasing Subsequence, LIS)问题要求我们找到一个数组中的最长严格递增子序列的长度。子序列是通过删除某些元素而不改变剩余元素的顺序得到的。例如,在数组 [10,9,2,5,3,7,101,18] 中,最长递增子序列是 [2,3,7,101],其长度为 4。

解题思路

  1. 动态规划(DP)方法
    • 使用一个数组 dp,其中 dp[i] 表示以 nums[i] 结尾的最长递增子序列的长度。
    • 初始化 dp 数组,每个位置都为 1(至少每个元素自身可以形成一个长度为 1 的子序列)。
    • 对于每个元素 nums[i],遍历之前的元素 nums[j]j < i),如果 nums[j] < nums[i],则更新 dp[i] = max(dp[i], dp[j] + 1)
    • 最终,最长递增子序列的长度为 max(dp)
  2. 优化方法(O(n log n))
    • 使用一个辅助数组 tails,其中 tails[k] 表示长度为 k+1 的递增子序列的末尾元素的最小值。
    • 遍历 nums 中的每个元素,使用二分查找在 tails 中找到第一个大于或等于当前元素的位置,更新 tails
    • 如果当前元素大于 tails 中的所有元素,则将其添加到 tails 的末尾。
    • 最终,tails 的长度即为最长递增子序列的长度。

C++ 实现

以下是使用动态规划和优化方法的 C++ 实现:

动态规划实现

#include <vector>
#include <algorithm>
#include <iostream>int lengthOfLIS(std::vector<int>& nums) {if (nums.empty()) return 0;std::vector<int> dp(nums.size(), 1);for (size_t i = 1; i < nums.size(); ++i) {for (size_t j = 0; j < i; ++j) {if (nums[j] < nums[i]) {dp[i] = std::max(dp[i], dp[j] + 1);}}}return *std::max_element(dp.begin(), dp.end());
}int main() {std::vector<int> nums = {10, 9, 2, 5, 3, 7, 101, 18};std::cout << "最长递增子序列的长度为: " << lengthOfLIS(nums) << std::endl;return 0;
}

优化方法实现(O(n log n))

#include <vector>
#include <algorithm>
#include <iostream>int lengthOfLIS(std::vector<int>& nums) {std::vector<int> tails;for (int num : nums) {auto it = std::lower_bound(tails.begin(), tails.end(), num);if (it == tails.end()) {tails.push_back(num);} else {*it = num;}}return tails.size();
}int main() {std::vector<int> nums = {10, 9, 2, 5, 3, 7, 101, 18};std::cout << "最长递增子序列的长度为: " << lengthOfLIS(nums) << std::endl;return 0;
}

总结

  • 动态规划的方法简单易懂,但时间复杂度为 O(n^2)。
  • 优化方法通过使用二分查找将时间复杂度降低到 O(n log n),适合处理较大的输入数据。

希望这个解答能帮助你理解最长递增子序列问题的解决方案!如果有任何疑问,欢迎继续提问。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • docker数据卷、资源控制
  • Java中Spring基础知识理解
  • 如何用剪映自动批量生成左右分屏的视频?
  • 080:vue+mapbox中interpolate 的详细解释
  • 【深度学习】【语音】TTS,MeloTTS代码讲解
  • 图像识别,图片线条检测
  • SpringBoot优雅开发REST API最佳实践
  • Socks5代理IP在跨境电商和网络爬虫领域的实战应用
  • 八种排序算法的复杂度(C语言)
  • C++-类与对象(中下篇)
  • docker compose部署rabbitmq集群,并使用haproxy负载均衡
  • 【Linux Install】Ubuntu20, Windows10 双系统安装
  • 学习记录第二十五天
  • 【MySQL进阶】事务、存储引擎、索引
  • 【解析几何笔记】2.向量及其线性运算
  • Laravel Telescope:优雅的应用调试工具
  • php ci框架整合银盛支付
  • 安卓应用性能调试和优化经验分享
  • 前嗅ForeSpider教程:创建模板
  • 系统认识JavaScript正则表达式
  • 一个普通的 5 年iOS开发者的自我总结,以及5年开发经历和感想!
  • 职业生涯 一个六年开发经验的女程序员的心声。
  • 曾刷新两项世界纪录,腾讯优图人脸检测算法 DSFD 正式开源 ...
  • 专访Pony.ai 楼天城:自动驾驶已经走过了“从0到1”,“规模”是行业的分水岭| 自动驾驶这十年 ...
  • ​人工智能之父图灵诞辰纪念日,一起来看最受读者欢迎的AI技术好书
  • #APPINVENTOR学习记录
  • #define
  • $jQuery 重写Alert样式方法
  • (4)(4.6) Triducer
  • (BAT向)Java岗常问高频面试汇总:MyBatis 微服务 Spring 分布式 MySQL等(1)
  • (C语言)fread与fwrite详解
  • (超简单)构建高可用网络应用:使用Nginx进行负载均衡与健康检查
  • (第8天)保姆级 PL/SQL Developer 安装与配置
  • (附源码)springboot 房产中介系统 毕业设计 312341
  • (三)SvelteKit教程:layout 文件
  • (已解决)报错:Could not load the Qt platform plugin “xcb“
  • (转)http-server应用
  • (转)ORM
  • (转)详解PHP处理密码的几种方式
  • .gitignore文件---让git自动忽略指定文件
  • .NET Framework 3.5安装教程
  • .Net Framework 4.x 程序到底运行在哪个 CLR 版本之上
  • .NET大文件上传知识整理
  • .net实现头像缩放截取功能 -----转载自accp教程网
  • ;号自动换行
  • @private @protected @public
  • @RequestMapping处理请求异常
  • @test注解_Spring 自定义注解你了解过吗?
  • @基于大模型的旅游路线推荐方案
  • [240607] Jina AI 发布多模态嵌入模型 | PHP 曝新漏洞 | TypeScript 5.5 RC 发布公告
  • [Android]使用Retrofit进行网络请求
  • [Angular] 笔记 9:list/detail 页面以及@Output
  • [bzoj1038][ZJOI2008]瞭望塔
  • [C#7] 1.Tuples(元组)
  • [Head First设计模式]策略模式