当前位置:首页 > 洛谷 > 洛谷P3902题解析:动态规划求解最长递增子序列(时间复杂度优化)

洛谷P3902题解析:动态规划求解最长递增子序列(时间复杂度优化)

2周前 (09-03)

洛谷P3902题解析:动态规划求解最长递增子序列(时间复杂度优化) 洛谷题解 动态规划 C++ 二分查找 递增子序列 第1张

一、题目解读

洛谷P3902题要求给定一个整数序列,计算将其转换为最长递增子序列所需的最小修改次数。题目核心在于寻找原序列与最长递增子序列之间的差异,通过算法优化求解效率。理解“修改次数”即原序列长度与最长递增子序列长度的差值,成为解题的关键突破口。

二、解题思路

采用动态规划(DP)与二分查找的结合策略。传统LIS(最长递增子序列)问题通常使用O(n^2)的动态规划,但此处通过维护一个递增序列dp,利用lower_bound函数将时间复杂度降至O(nlogn)。核心思想是:每次遍历原序列元素时,找到dp中第一个大于等于该元素的位置,替换或扩展dp序列,最终dp的长度即为LIS长度。

三、解题步骤

1. 输入与初始化:读取序列n及元素,初始化动态规划数组dp为空。

2. 循环遍历:对每个元素num,通过二分查找找到dp中第一个不小于num的位置it。

3. 替换/扩展:

○ 若it为dp末尾(表示num大于所有现有元素),则扩展dp:dp.push_back(num)。

○ 否则替换it位置元素:*it = num(保证dp始终递增且长度最短)。

4. 输出结果:最终修改次数为n - dp.size(),即原序列长度减去LIS长度。

四、代码及注释

#include <bits/stdC++.h>
using namespace std;

const int MAXN = 1e5+5;

int main() {
    ios::sync_with_stdio(false); // 加快输入/输出速度
    cin.tie(0);
    
    int n;
    cin >> n; // 输入序列长度
    vector<int> nums(n); // 存储原序列
    for(int i=0; i<n; i++) {
        cin >> nums[i];
    }
    
    // 计算最长递增子序列长度
    vector<int> dp; // 动态规划数组,存储递增子序列
    for(int num : nums) {
        // 使用lower_bound找到第一个不小于当前元素的位置
        auto it = lower_bound(dp.begin(), dp.end(), num);
        if(it == dp.end()) { // 若num大于所有dp元素,扩展序列
            dp.push_back(num);
        } else { // 替换第一个不小于num的元素(缩短dp长度)
            *it = num;
        }
    }
    
    // 需要修改的次数 = 总长度 - 最长递增子序列长度
    cout << n - dp.size() << endl;
    return 0;
}

五、总结

本解法通过动态规划与二分查找的结合,巧妙地将LIS问题的时间复杂度优化至线性对数级别。关键在于维护递增序列dp并利用lower_bound精准定位替换位置,避免重复元素,从而高效计算修改次数。此思路对处理大规模数据的长递增子序列问题具有重要参考价值,同时为算法优化提供了实践范例。


原创内容 转载请注明出处

分享给朋友:

相关文章

力扣119题:从O(n²)到O(2n):杨辉三角高效空间优化

力扣119题:从O(n²)到O(2n):杨辉三角高效空间优化

题目重解:给定一个非负索引 rowIndex,返回杨辉三角的第 rowIndex 行。不同于生成整个杨辉三角,这道题要求我们只返回特定行,且空间复杂度应尽可能优化。例如输入3,需要返回[1,3,3,1...

【动态规划入门】力扣509题:斐波那契数列的经典解法与优化思路

【动态规划入门】力扣509题:斐波那契数列的经典解法与优化思路

题目解读‌斐波那契数列是一个经典的数学问题,在计算机科学中常被用作算法教学的入门案例。这个神奇的数列从0和1开始,后续每个数字都是前两个数字之和。题目要求我们计算第n个斐波那契数,看似简单的问题背后却...

力扣965题深度解析:单值二叉树的判断技巧

力扣965题深度解析:单值二叉树的判断技巧

重新解读题目 判断一棵二叉树是否为“单值二叉树”,即所有节点的值是否完全相同。题目看似简单,实则考验对树结构递归特性的理解。若一棵树的所有节点值相同,其必然满足:根节点与左右子树的值一致,且...

力扣540题:线性扫描法如何高效定位唯一数

力扣540题:线性扫描法如何高效定位唯一数

题目重解一个严格递增的有序数组中,除某个元素外,其余每个元素均出现两次。这个看似简单的条件背后隐藏着巧妙的规律——单一元素会打破数组的"成对对称性"。题目要求以O(log n)时间...

CSP-J 2019纪念品题解(洛谷P5662):动态规划+完全背包问题的实战应用

CSP-J 2019纪念品题解(洛谷P5662):动态规划+完全背包问题的实战应用

一、题目解读2019年CSP-J的“纪念品”问题(对应洛谷P5662)要求玩家在T天内通过买卖纪念品最大化金币收益。每天可交易N种商品,需计算最优策略下的最终金币数。题目强调动态规划思维与资源分配优化...

手搓顺序表类代码注释与详解:从零实现动态数组(新手教程)

一、简介和特点顺序表(Sequential List)是数据结构中基础的一种线性表,其特点是将数据元素存储在连续的内存空间中。通过数组实现,支持随机访问(即通过索引直接访问元素),适用于频繁随机读取的...

发表评论

访客

看不清,换一张

◎欢迎参与讨论,请在这里发表您的看法和观点。