📅  最后修改于: 2023-12-03 14:54:29.157000             🧑  作者: Mango
在一个序列中,如果存在一段先递增后递减(或者先递减后递增)的子序列,那么这个子序列就是双调的。最长双调子序列是指在一个序列中,最长的双调子序列的长度。空间优化方法是可以用较小的空间实现高效算法的一种方法。
以下介绍最长双调子序列(空间优化方法)的算法实现:
up_len
: 以 i
结尾的最长递增子序列的长度down_len
: 以 i
开头的最长递减子序列的长度seq
: 输入的序列up_len
和 down_len
,长度均为序列长度,并初始化为1up_len[i]
的值,即以 i
结尾的最长递增子序列的长度j
,如果 seq[i] > seq[j]
且 up_len[i] < up_len[j]+1
,则 up_len[i] = up_len[j]+1
down_len[i]
的值,即以 i
开头的最长递减子序列的长度j
,如果 seq[i] > seq[j]
且 down_len[i] < down_len[j]+1
,则 down_len[i] = down_len[j]+1
up_len[i]
和 down_len[i]
相加,求得以 i
为转折点的最长双调子序列的长度 length[i]
,同时记录转折点的位置 pivot[i]
pivot
和 length
,从 seq
中输出最长双调子序列该算法时间复杂度为 $O(n^2)$,与经典的最长递增子序列算法相同。但由于使用了空间优化,所需空间为 $O(n)$,而不是 $O(n^2)$,因此可以较好地处理大规模数据。
def print_longest_bitonic_subsequence(seq):
n = len(seq)
up_len = [1 for _ in range(n)]
down_len = [1 for _ in range(n)]
pivot = [0 for _ in range(n)]
length = [0 for _ in range(n)]
for i in range(n):
for j in range(i):
if seq[i] > seq[j] and up_len[i] < up_len[j]+1:
up_len[i] = up_len[j]+1
for i in range(n-1, -1, -1):
for j in range(i+1, n):
if seq[i] > seq[j] and down_len[i] < down_len[j]+1:
down_len[i] = down_len[j]+1
max_length, max_pivot = 0, 0
for i in range(n):
length[i] = up_len[i] + down_len[i] - 1
pivot[i] = i
if length[i] > max_length:
max_length = length[i]
max_pivot = i
output_seq = []
for i in range(max_pivot, -1, -1):
if length[i] == max_length and seq[i] not in output_seq:
output_seq.append(seq[i])
for i in range(max_pivot+1, n):
if length[i] == max_length and seq[i] not in output_seq:
output_seq.append(seq[i])
print(output_seq)