📌  相关文章
📜  教资会网络 | UGC-NET CS 2017 年 11 月 – III |问题 52(1)

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

UGC-NET CS 2017 年 11 月 – III | 问题 52

本题涉及动态规划和最长上升子序列(LIS)的问题。

问题描述

给定一个整数序列 $A=(a_1, a_2, ..., a_n)$,求其最长上升子序列长度。

解题思路
动态规划

$dp[i]$ 表示以 $a_i$ 结尾的最长上升子序列长度。则对于 $i<j$,若 $a_j>a_i$,则有 $dp[j]=\max(dp[j], dp[i]+1)$。

初始化 $dp[i]=1$。

最终答案为 $\max(dp[i])$。

时间复杂度 $O(n^2)$。

代码片段:

dp = [1] * n
for i in range(1, n):
    for j in range(i):
        if a[j] < a[i]:
            dp[i] = max(dp[i], dp[j] + 1)
print(max(dp))
LIS

注意到 $dp[i]$ 只和 $dp[0...i-1]$ 有关,可以使用二分查找进行优化。

用数组 $d[i]$ 记录长度为 $i$ 的 LIS 的最小末尾元素。

对每个元素 $a_i$,若 $a_i > d[length]$,则 $length$ 自增,否则在 $d$ 的 $[1,length]$ 中二分查找最小的 $d[k]$ 满足 $a_i\le d[k]$,并令 $d[k]=a_i$。

最终返回 $length$。

时间复杂度 $O(n\log n)$。

代码片段:

length = 0
d = [0] * (n + 1)
for i in range(n):
    if a[i] > d[length]:
        length += 1
        d[length] = a[i]
    else:
        pos = bisect_left(d, a[i], lo=1, hi=length)
        d[pos] = a[i]
print(length)
总结

本题可以使用动态规划或 LIS 求解。

LIS 使用了二分查找优化,时间复杂度更优。

代码中需要注意数组索引和二分查找的参数。

代码示例以 Python 为例,其他语言类似。