《最长单调子序列》基础概念

一、算法概述

  1. 问题定义:给定一个整数序列,找到其中最长的严格递增(递减)子序列的长度。子序列中的元素不需要连续,但必须保持原序列的顺序。例如,序列 [10, 9, 2, 5, 3, 7, 101, 18] 的最长递增子序列是 [2, 3, 7, 101],长度为 4。

  2. 应用场景:该算法在生物信息学(DNA序列分析)、数据压缩和计算机视觉等领域有广泛应用。

二、算法思路

  1. 动态规划思想:维护一个辅助数组 g,其中 g[i] 表示长度为 i 的递增子序列的最小可能末尾元素。通过贪心策略和二分查找优化,高效地更新该数组。

  2. 核心策略:对于每个元素,尝试将其插入或替换到辅助数组 g 中的适当位置,以保持数组的单调性。插入位置由二分查找确定。

  3. 关键性质

    • 数组 g 始终保持严格递增。
    • 数组 g 的长度即为当前找到的最长递增子序列的长度。

三、伪代码实现

算法:最长递增子序列(贪心+二分优化)
输入:数组 a[0..n-1],数组长度 n
输出:最长递增子序列的长度

function getLIS(n, a[]):
    // g[i] 表示长度为 i+1 的递增子序列的最小末尾元素
    g[0..n-1]
    gSize = 0  // 当前最长递增子序列的长度
    
    for i = 0 to n-1:
        // 二分查找插入位置
        l = -1, r = gSize
        while l + 1 < r:
            mid = (l + r) / 2  // 向下取整
            if g[mid] >= a[i]:
                r = mid
            else:
                l = mid
        
        // 插入或替换操作
        if r == gSize:
            g[gSize] = a[i]
            gSize = gSize + 1
        else:
            g[r] = a[i]
    
    return gSize

// 主程序
输入 n
输入数组 a[0..n-1]
输出 getLIS(n, a)

四、算法解释

  1. 初始化阶段

    • 创建辅助数组 g 用于存储递增子序列的最小末尾元素。
    • gSize 记录当前最长递增子序列的长度,初始为 0。
  2. 遍历处理每个元素

    • 二分查找:对于每个元素 a[i],在 g 中找到第一个大于或等于 a[i] 的位置 r
    • 插入或替换
      • 如果 r 等于当前 gSize,说明 a[i] 可以扩展当前最长子序列,将其添加到 g 的末尾。
      • 否则,将 g[r] 替换为 a[i],以减小长度为 r+1 的子序列的末尾元素,为后续扩展提供可能。
  3. 示例演示

    • 输入数组 [3, 1, 2, 5, 4, 6]
    • 处理过程:
      • 处理 3:g = [3],长度 1。
      • 处理 1:g = [1],替换 3。
      • 处理 2:g = [1, 2],扩展长度。
      • 处理 5:g = [1, 2, 5]
      • 处理 4:g = [1, 2, 4],替换 5。
      • 处理 6:g = [1, 2, 4, 6],最终长度为 4。
  4. 正确性证明

    • 数组 g 始终保持严格递增,确保二分查找的正确性。
    • 通过替换操作,贪心策略保证了每个长度的子序列末尾元素尽可能小,从而允许后续元素更容易扩展。

五、复杂度分析

  1. 时间复杂度 O ( n l o g n ) O(n log n) O(nlogn),其中 n n n 是数组长度。每个元素的处理需要 O ( l o g n ) O(log n) O(logn) 的二分查找。
  2. 空间复杂度 O ( n ) O(n) O(n),主要用于存储辅助数组 g
  3. 与朴素 DP 的对比:传统动态规划方法的时间复杂度为 O ( n 2 ) O(n²) O(n2),而本算法通过贪心和二分优化将复杂度降低到 O ( n l o g n ) O(n log n) O(nlogn),适用于大规模数据。

  本文为作者(英雄哪里出来)在抖音的独家课程《英雄C++入门到精通》、《英雄C语言入门到精通》、《英雄Python入门到精通》三个课程的配套文字讲解,如需了解算法视频课程,请移步 作者本人 的抖音直播间。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

英雄哪里出来

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值