我有一组整数。我想使用动态规划找到该集合的最长递增子序列。
我有一组整数。我想使用动态规划找到该集合的最长递增子序列。
def lis_dp(array):
alias = [1] * len(array)
for i in range(1, len(array)):
for j in range(0, i):
if array[i] > array[j]:
alias[i] = max(alias[i], alias[j] + 1)
output = max(alias)
return output
arr = [4, 10, 6, 5, 8, 11, 2, 20]
output = lis_dp(array=arr)
print(output)
方法一时间复杂度分析:由于此代码中使用了两个for循环,因此时间复杂度为theta(n^2)。
第二种方法:使用二分查找
这个问题可以在theta(nlog(n))的时间内解决。
理论:
构建尾数组,并且尾数组的长度就是答案。
tail[i]存储着LIS(最长递增子序列)长度为(i + 1)时的最小可能尾值,其中i的范围为(0, n),n是给定数组的长度。
创建尾数组时的两个条件
条件1:如果要插入到尾数组中的下一个元素大于前一个元素,则将该元素追加到尾部。
条件2:如果要插入到尾数组中的下一个元素小于前一个元素,则将其替换为左侧最接近它的元素。
特殊情况
情况1:如果我们有按降序排列的数组,则输出为1。
情况2:如果我们有按升序排列的数组,则输出为数组的长度。def ceil_idx(tail, x):
l = 0
r = len(tail) - 1
while r > l:
m = l + (r - l)//2
if tail[m] >= x:
r = m
else:
l = m + 1
return r
def lis_bs(array):
n = len(array)
tail = [array[0]]
for i in range(1, n):
# condition 1: If the next element to be inserted in the tail array is greater than previous one, then element is appended.
if array[i] > tail[-1]:
tail.append(array[i])
else:
# condition 2: If the next element to be inserted in the tail array is smaller than previous element then it will replace it ceiling to its left.
c = ceil_idx(tail, array[i])
tail[c] = array[i]
return len(tail)
arr = [4, 10, 6, 5, 8, 11, 2, 20]
output_lis = lis_bs(array=arr)
print(output_lis)
第二种方法的时间复杂度分析
由于存在一个循环,它运行到数组的长度,因此需要 theta(n) 的时间,并且在这个循环内部还有另一个函数运行,即二分查找(天花板函数),它需要 log(n) 的时间,因此总共需要 nlog(n) 的时间。