📅  最后修改于: 2023-12-03 14:49:15.231000             🧑  作者: Mango
有一个长度为 $n$ 的数组 $a$,现在你有一次操作机会,可以在数组中任意位置插入一个整数。你需要找到在这次操作后,最长的连续子序列的长度。
假设插入的整数是 $x$,我们可以用两个数组 $f$ 和 $g$ 分别记录:
那么最终的答案就是 $\max\limits_{i=1}^n {f_i+g_i-1}$。其中减一是因为 $x$ 被算了两次。
具体地,则可以利用动态规划的思想从左往右求出 $f$ 数组,然后从右往左求出 $g$ 数组。这两个过程可以分别用时间复杂度为 $O(n\log n)$ 的 LIS(最长上升子序列)算法求解。
下面是用 Python 3 实现的代码:
from bisect import bisect_left
def LIS(a):
"""
返回一个数组的最长上升子序列的长度。
"""
n = len(a)
f = [-1] * n # f[i] 表示以 a[i] 结尾的 LIS 长度。
prev = [-1] * n # prev[i] 表示 a[i] 前面的 LIS 中的前驱节点。
lis = [] # lis[i] 表示长度为 i+1 的 LIS 中的最后一个节点。
length = 0 # 当前 LIS 的长度。
for i in range(n):
j = bisect_left(lis, a[i])
f[i] = j + 1
prev[i] = -1 if j == 0 else lis[j-1]
if j == length:
lis.append(a[i])
length += 1
else:
lis[j] = min(lis[j], a[i])
return f
def longest_continuous_subsequence(a):
"""
返回对数组 a 只能做一次插入操作后最长的连续子序列的长度。
"""
n = len(a)
f = LIS(a)
g = LIS(a[::-1])[::-1]
return max(f[i]+g[i]-1 for i in range(n))
# 示例:最长连续子序列为 [3,4,5]
a = [1, 3, 5, 2, 6]
print(longest_continuous_subsequence(a)) # 3
本算法的时间复杂度为 $O(n\log n)$,其中 LIS 算法的时间复杂度为 $O(n\log n)$。