import bisect
def lis(xs):
ret = []
for x in xs:
i = bisect.bisect_left(ret, x)
ret[i:i+1] = x,
return len(ret)
例子:
>>> lis([10, 1, 2, 3])
3
>>> lis([10,22,9,33,21,50,41,60,80])
6
注意:在上面的代码中,
ret
不包含有效子序列。但长度是正确的。
如果您想要的只是 LIS 的长度,请使用上述代码。
解释:
考虑
[10,22,9,11]
。可能有两个 LIS:
[10,22]
、
[9,11]
。上述
lis
函数中的
ret
维护以下条件:
ret
已排序;可以使用二分查找(bisect.bisect_left)
ret[i]
包含长度为 i
的子序列的最小末尾值。
ret
的变化如下...(以给定输入 [10,22,9,11]
为例)
- [10] - 处理第一个元素后
- [10, 22] - 处理第二个元素后
- [9, 22] - ... 现在长度为1的子序列的最小值是9!10被覆盖了。
- [9, 11]
时间复杂度:O(nk),其中 n 是列表项数,k 是 LIS 的长度。
更新
修改版,可以正确获取子序列:
import bisect
def lis(xs):
if not xs: return []
prev = {}
ret = []
for x in xs:
i = bisect.bisect_left(ret, x)
ret[i:i+1] = x,
prev[x] = ret[i-1] if i > 0 else None
subseq = [ret[-1]]
while subseq[-1] is not None:
subseq.append(prev[subseq[-1]])
return list(reversed(subseq[:-1]))
例子:
>>> lis([])
[]
>>> lis([10, 1, 2, 3])
[1, 2, 3]
>>> lis([10,22,9,33,21,50,41,60,80])
[10, 22, 33, 41, 60, 80]
>>> lis([1,5,2,6,3,4])
[1, 2, 3, 4]
>>> lis([100,200,1,2,3])
[1, 2, 3]