📌  相关文章
📜  从两端生成具有相同大小 LIS 的 N 长度排列(1)

📅  最后修改于: 2023-12-03 15:36:16.007000             🧑  作者: Mango

从两端生成具有相同大小 LIS 的 N 长度排列

本文介绍如何在一个长度为 N 的排列中,从两端依次取数,生成两个具有相同大小的最长上升子序列(LIS)。

问题描述

给定一个长度为 N 的排列,如何从两端依次取数,生成两个具有相同大小的最长上升子序列?

解决方案

一种思路是从中间位置开始往两端进行扩展,直到两边能够生成相同大小的 LIS。

步骤:
  1. 找到中间位置 mid = N / 2,将排列分为左右两部分。
  2. 左边部分从中心开始往左扩展,右边部分从中心开始往右扩展,直到两边的长度相同。
  3. 对于左边部分,进行求 LIS 操作。对于右边部分,以相反顺序进行求 LIS 操作。(可以使用动态规划来求 LIS)
  4. 最后将两个 LIS 进行合并,得到一个具有相同大小的最长上升子序列。
代码实现:
def get_LIS_from_both_ends(arr: List[int]) -> List[int]:
    # 排序
    arr = sorted(arr)
    # 找到中间位置
    mid = len(arr) // 2
    left, right = arr[:mid], arr[mid:]
    # 求左侧 LIS
    dp_left = [1] * len(left)
    for i in range(1, len(left)):
        for j in range(i):
            if left[j] < left[i]:
                dp_left[i] = max(dp_left[i], dp_left[j] + 1)
    # 求右侧 LIS
    dp_right = [1] * len(right)
    for i in range(len(right)-2, -1, -1):
        for j in range(len(right)-1, i, -1):
            if right[j] < right[i]:
                dp_right[i] = max(dp_right[i], dp_right[j] + 1)
    # 合并两个 LIS,得到一个具有相同大小的最长上升子序列
    lis = []
    for i in range(len(dp_left)):
        if dp_left[i] == dp_right[i]:
            lis = left[:i+1] + right[len(right)-i-1:]
            break
    return lis
时间复杂度

本方法的时间复杂度为 O(N^2),其中 N 为排列的长度。

总结

本文介绍了如何在一个长度为 N 的排列中,从两端依次取数,生成两个具有相同大小的最长上升子序列。这个问题可以通过从中间位置开始往两端进行扩展来解决。在得到左右两边的 LIS 之后,进行合并得到一个具有相同大小的最长上升子序列。