当前位置:首页 > 洛谷 > 洛谷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精准定位替换位置,避免重复元素,从而高效计算修改次数。此思路对处理大规模数据的长递增子序列问题具有重要参考价值,同时为算法优化提供了实践范例。


原创内容 转载请注明出处

分享给朋友:

相关文章

力扣746:三步通关最小花费爬楼梯

力扣746:三步通关最小花费爬楼梯

题目解析:站在楼梯的某个台阶时,需要支付当前台阶对应的体力值cost[i],之后可以选择向上爬1或2个台阶。最终目标是到达‌楼层顶部‌(即数组末尾之后的位置),且初始位置可选择下标0或1的台阶作为起点...

征服力扣704题:三步掌握经典二分查找算法

征服力扣704题:三步掌握经典二分查找算法

题目重解我们面对的是算法领域最经典的二分查找问题:在一个已排序的整数数组中,快速定位目标值的位置。就像在一本按字母顺序排列的字典中查找单词,我们不需要逐页翻阅,而是通过不断折半的方式快速缩小搜索范围,...

力扣654:递归分治的艺术 如何用最大元素构建二叉树

力扣654:递归分治的艺术 如何用最大元素构建二叉树

题目重解我们面对一个看似简单却充满递归魅力的题目:给定一个不含重复元素的整数数组,需要构建一棵特殊的二叉树。这个树的每个父节点都必须是当前子数组中的最大元素,而它的左右子树则分别由该最大值左侧和右侧的...

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

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

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

CSP-J方格取数题解|动态规划解法|洛谷P7074代码解析

CSP-J方格取数题解|动态规划解法|洛谷P7074代码解析

一、题目解读题目要求在一个n×m的网格中,从左上角到右下角选择一条路径,路径上的数字可重复取用,求取数之和的最大值。路径限制为仅能向右或向下移动。需注意路径的灵活性与重复取数的可能性,传统单向动态规划...

LeetCode 120题三角形最小路径和最优解法:动态规划详解与代码实现

LeetCode 120题三角形最小路径和最优解法:动态规划详解与代码实现

一、题目解读LeetCode 120题“三角形最小路径和”要求给定一个由数字组成的三角形,从顶部开始向下移动,每次可向左或向右移动一格,计算从顶至底的最小路径和。三角形以二维向量形式给出,每层元素数量...

发表评论

访客

看不清,换一张

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