因为只有定义 dp[i] 为“以 nums[i] 结尾的最长递增子序列长度”,才能通过比较 nums[j]
为什么
dp[i]定义成“以nums[i]结尾的最长递增子序列长度”才对很多初学者会误把
dp[i]理解为“前i个元素中的 LIS 长度”,但这会导致状态无法转移:你没法从dp[i-1]推出dp[i],因为新增的nums[i]可能接不上前面任何子序列的末尾。只有定义成“以nums[i]结尾”,才能明确判断:对所有j 且 <code>nums[j] ,尝试用 <code>dp[j] + 1更新dp[i]。这个定义让状态转移有依据,也保证每个
dp[i]是可计算、可验证的局部最优。标准 O(n²) 动态规划写法要注意什么
核心是两层循环 + 条件更新。容易漏掉的点:
dp数组必须初始化为1(每个元素自身构成长度为 1 的递增子序列)- 内层循环
j必须从0到i-1,不能只看前一个- 更新条件严格是
nums[j] ,不是 <code>- 最终答案不是
dp[n-1],而是整个dp数组的最大值vector<int> nums = {10, 9, 2, 5, 3, 7, 101, 18}; int n = nums.size(); vector<int> dp(n, 1); for (int i = 1; i < n; ++i) { for (int j = 0; j < i; ++j) { if (nums[j] < nums[i]) { dp[i] = max(dp[i], dp[j] + 1); } } } int ans = *max_element(dp.begin(), dp.end()); // ans = 4想优化到 O(n log n)?必须换思路用贪心 + 二分
O(n²) 在
n > 10⁴时可能超时。lower_bound优化的关键不是加速 DP,而是放弃记录所有可能结尾,转而维护一个数组tail,其中tail[len]表示长度为len+1的递增子序列的最小可能末尾值。立即学习“C++免费学习笔记(深入)”;
这样做的好处:
tail始终严格递增 → 支持二分查找- 每次用
nums[i]替换第一个 ≥ 它的tail[k],或追加到末尾- 最终
tail.size()就是 LIS 长度(但tail本身不一定是真实子序列)vector<int> nums = {10, 9, 2, 5, 3, 7, 101, 18}; vector<int> tail; for (int x : nums) { auto it = lower_bound(tail.begin(), tail.end(), x); if (it == tail.end()) { tail.push_back(x); } else { *it = x; } } int ans = tail.size(); // ans = 4如果需要输出任意一个 LIS,而不是只求长度
O(n²) 方法可以回溯,O(n log n) 方法也可以,但要额外维护两个数组:
dp[i]:以i结尾的 LIS 长度(仍需 O(n²) 计算)prev[i]:在最优路径中,i的前一个索引(即哪个j贡献了最大dp[j]+1)- 找到
dp最大值对应的位置idx,然后沿prev[idx]回溯构造结果注意:
prev数组初始化为-1,回溯时要逆序插入,最后反转才是正序 LIS。真正难的不是写对算法,而是意识到:O(n log n) 版本天生不保存路径信息;要输出序列,要么接受 O(n²) 时间,要么在贪心版本里同步维护索引映射——后者代码复杂度陡增,实际项目中建议优先确认是否真需要输出子序列本身。
0
0
相关文章
如何用c++实现一个行为树(Behavior Tree)? (游戏AI逻辑)
c++中如何求矩阵的转置_c++二维数组矩阵转置代码
C++如何实现一个A*寻路算法?C++游戏AI与路径规划【算法实战】
c++在Unreal Engine中的应用_c++ UE4/5游戏开发基础
如何用C++实现一个有限状态机(FSM)?C++游戏AI与协议解析【设计模式】
本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
热门AI工具
相关专题
本专题围绕 C# 在现代后端架构中的微服务实践展开,系统讲解基于 ASP.NET Core 构建可扩展服务体系的核心方法。内容涵盖服务拆分策略、RESTful API 设计、服务间通信、API 网关统一入口管理以及服务治理机制。通过真实项目案例,帮助开发者掌握构建高可用微服务系统的关键技术,提高系统的可扩展性与维护效率。
76
2026.03.11
本专题围绕 Go 语言在高并发任务处理场景中的实践展开,系统讲解 Goroutine 调度模型、Channel 通信机制以及并发控制策略。内容包括任务队列设计、Goroutine 池化管理、资源限制控制以及并发任务的性能优化方法。通过实际案例演示,帮助开发者构建稳定高效的 Go 并发任务处理系统,提高系统在高负载环境下的处理能力与稳定性。
38
2026.03.10
本专题围绕 Kotlin 在 Android 应用开发中的架构实践展开,重点讲解模块化设计与组件化开发的实现思路。内容包括项目模块拆分策略、公共组件封装、依赖管理优化、路由通信机制以及大型项目的工程化管理方法。通过真实项目案例分析,帮助开发者构建结构清晰、易扩展且维护成本低的 Android 应用架构体系,提升团队协作效率与项目迭代速度。
83
2026.03.09
本专题围绕 JavaScript 在浏览器中的执行与渲染机制展开,系统讲解 DOM 构建、CSSOM 解析、重排与重绘原理,以及关键渲染路径优化方法。内容涵盖事件循环机制、异步任务调度、资源加载优化、代码拆分与懒加载等性能优化策略。通过真实前端项目案例,帮助开发者理解浏览器底层工作原理,并掌握提升网页加载速度与交互体验的实用技巧。
97
2026.03.06
本专题围绕 Rust 语言核心特性展开,深入讲解所有权机制、借用规则、生命周期管理以及智能指针等关键概念。通过系统级开发案例,分析内存安全保障原理与零成本抽象优势,并结合并发场景讲解 Send 与 Sync 特性实现机制。帮助开发者真正理解 Rust 的设计哲学,掌握在高性能与安全性并重场景中的工程实践能力。
223
2026.03.05
本专题围绕 PHP 在现代 Web 后端开发中的高性能实践展开,重点讲解基于 Laravel 框架构建可扩展 API 服务的核心方法。内容涵盖路由与中间件机制、服务容器与依赖注入、接口版本管理、缓存策略设计以及队列异步处理方案。同时结合高并发场景,深入分析性能瓶颈定位与优化思路,帮助开发者构建稳定、高效、易维护的 PHP 后端服务体系。
458
2026.03.04
2026最全AI工具安装教程专题:包含各版本AI绘图、AI视频、智能办公软件的本地化部署手册。全篇零基础友好,附带最新模型下载地址、一键安装脚本及常见报错修复方案。每日更新,收藏这一篇就够了,让AI安装不再报错!
169
2026.03.04
本专题聚焦 Swift 在 iOS 应用架构设计中的实践,系统讲解 MVVM 模式的核心思想、数据绑定机制、模块拆分策略以及组件化开发方法。内容涵盖网络层封装、状态管理、依赖注入与性能优化技巧。通过完整项目案例,帮助开发者构建结构清晰、可维护性强的 iOS 应用架构体系。
246
2026.03.03
热门下载
相关下载
精品课程
最新文章




