排序算法之:Patience Sorting(耐心排序)的最长递增子序列应用与优化策略
字数 1364 2025-11-27 18:53:16
排序算法之:Patience Sorting(耐心排序)的最长递增子序列应用与优化策略
题目描述
给定一个整数数组 nums,使用耐心排序算法找出其最长递增子序列(Longest Increasing Subsequence, LIS)的长度。要求详细讲解耐心排序的原理、如何通过它求解 LIS 长度,并分析优化策略。
解题过程
1. 耐心排序的基本原理
耐心排序是一种基于分组的排序算法,其核心思想是将元素依次分配到若干堆(pile)中,遵循两条规则:
- 规则1:每个堆顶元素按非递减顺序排列(即堆顶从左到右递增)。
- 规则2:每个新元素
x必须放入最左侧堆顶 ≥x的堆中(保证堆顶有序)。若没有满足条件的堆,则新建一个堆。
示例:对数组 [3, 1, 4, 2, 5] 的耐心排序过程:
- 初始:无堆。
- 3 → 新建堆1:
[3] - 1(1 < 3)→ 堆1顶替换为1:
[1] - 4(4 > 1)→ 新建堆2:
[1, 4](堆顶为1和4) - 2(2介于1和4之间)→ 放入堆2(堆顶4≥2):堆2顶变为2 →
[1, 2] - 5(5 > 2)→ 新建堆3:
[1, 2, 5]
最终堆数 = 3。
2. 耐心排序与最长递增子序列(LIS)的关系
关键结论:耐心排序的堆数等于最长递增子序列的长度。
- 每个堆对应LIS中的一个元素分组,堆的生成顺序隐含了递增子序列的构造逻辑。
- 数学证明(直观理解):每个堆保存一个递减序列,而不同堆的堆顶组成一个递增序列。堆数即为最长递增子序列长度。
3. 算法实现步骤
步骤1:初始化一个空列表 piles 存储堆顶元素。
步骤2:遍历数组中的每个元素 x:
- 在
piles中使用二分查找找到第一个堆顶 ≥x的位置。 - 若找到,用
x替换该堆顶(保证堆顶有序);若未找到,在末尾新建堆(即添加x)。
步骤3:最终piles的长度即为 LIS 的长度。
示例详析:nums = [10, 9, 2, 5, 3, 7, 101, 18]
- 10 → piles =
[10] - 9(替换10)→ piles =
[9] - 2(替换9)→ piles =
[2] - 5(新建堆)→ piles =
[2, 5] - 3(替换5)→ piles =
[2, 3] - 7(新建堆)→ piles =
[2, 3, 7] - 101(新建堆)→ piles =
[2, 3, 7, 101] - 18(替换101)→ piles =
[2, 3, 7, 18]
LIS长度 = 4(如[2, 5, 7, 101]或[2, 3, 7, 18])。
4. 优化策略
- 二分查找优化:维护
piles为有序数组,每次查找插入位置的时间为 O(log L),整体复杂度 O(N log L)(L为LIS长度)。 - 空间优化:仅需存储堆顶,空间复杂度 O(L)。
- 扩展应用:若需输出具体LIS,需额外记录每个元素的前驱指针(通过回溯堆中历史版本实现)。
5. 总结
耐心排序将LIS问题转化为维护有序堆顶的过程,通过二分查找保证高效性。该算法是求解LIS长度的最优方法之一,兼顾时间(O(N log N))和空间效率。