📜  构成排序序列的最小删除数(1)

📅  最后修改于: 2023-12-03 14:55:31.190000             🧑  作者: Mango

构成排序序列的最小删除数

在给定一个整数序列的情况下,我们可以通过删除其中某些元素,使其成为一个已排序的序列。那么最小需要删除多少元素,才能实现这个目标呢?

解题思路

设 $dp[i]$ 表示以第 $i$ 个元素为结尾的最长递增子序列的长度。显然,对于一个长度为 $n$ 的序列,我们需要删除的元素个数就是 $n - \max{dp[i]}$。因此,问题转化为求以每个元素为结尾的最长递增子序列。

对于一个新加入的元素 $nums[i]$,它可能与前面的某些元素构成最长递增子序列。具体地,我们可以枚举在 $i$ 之前的所有元素 $nums[j]$,若 $nums[j] < nums[i]$,则 $nums[j]$ 可以接在 $j$ 对应的最长递增子序列的结尾,从而得到一个新的长度为 $dp[j]+1$ 的递增子序列,而选不选取 $nums[j]$ 就要看哪个方案能使得最终的子序列最长,即选取长度最大的那个 $dp[j]+1$。在枚举所有元素之后,以 $nums[i]$ 结尾的最长递增子序列就是所有方案中长度的最大值。

具体实现可以用动态规划的思想,从前往后依次求出每个位置上的 $dp$ 值。注意到在枚举之前的元素时,我们要同时更新最大子序列的起点和终点,以便后面输出子序列。

代码实现

下面是 Python 代码的实现,时间复杂度为 $O(n^2)$,其中 $n$ 是序列长度:

def min_deletion(nums):
    n = len(nums)
    dp = [1] * n
    for i in range(1, n):
        for j in range(i):
            if nums[j] < nums[i]:
                dp[i] = max(dp[i], dp[j] + 1)
    max_len = max(dp)
    start = dp.index(max_len)
    end = start
    res = []
    for i in range(start, -1, -1):
        if nums[i] < nums[start] and dp[i] == dp[start] - (start - i):
            start = i
            res.append(nums[i])
    return n - max_len, res[::-1] + [nums[end]]
示例说明
>>> nums = [1, 5, 3, 4, 6, 9, 7, 8]
>>> min_deletion(nums)
(2, [1, 5, 6, 9])

对于一个输入序列 [1, 5, 3, 4, 6, 9, 7, 8],输出为 (2, [1, 5, 6, 9]),表示最小需要删除的元素个数为 $2$,满足要求的最长递增子序列为 [1, 5, 6, 9]。其中 $2$ 个被删除的元素为 $3$ 和 $7$。