LIS & LCS
最长递增子序列(LIS)
在计算机科学中,最长递增子序列(longest increasing subsequence)问题是指,在一个给定的数值序列中,找到一个子序列,使得这个子序列元素的数值依次递增,并且这个子序列的长度尽可能地大。最长递增子序列中的元素在原序列中不一定是连续的。许多与数学、算法、随机矩阵理论、表示论相关的研究都会涉及最长递增子序列。解决最长递增子序列问题的算法最低要求O(n log n)的时间复杂度,这里n表示输入序列的规模。——百度百科
LIS的一种做法是 O ( n 2 ) O(n^2) O(n2) 的复杂度,显然效率不高。这里我记录一下 O ( n log n ) O(n\log n) O(nlogn) 的做法。
用 f [ i ] f[i] f[i] 表示所有数 ( a [ i ] a[i] a[i] 到 a [ n ] a[n] a[n] ) 组成的LIS中,所有长度为 i i i 的LIS的末尾元素中最小值。我们需要从 a [ 1 ] a[1] a[1] 遍历到 a [ n ] a[n] a[n] ,用每个数组元素更新我们的 f f f 数组。用一个变量 l e n len len ,来记录我们当前最长LIS的长度。
如果 f[len] < a[i]
,那么 a [ i ] a[i] a[i] 就可以接在当前最长的(长度为 l e n len len)的LIS之后,就得到一个新的更长的LIS,相应的操作就是 f[++len] = a[i]
。
如果 a [ i ] a[i] a[i] 不能使LIS的长度增加,那么它一定相对比较小,那么,我们是否可以用它来优化 f f f 数组呢?他总是替换 f f f 数组从左往右第一个大于它的数。换句话说,它总是接在从左往右最后一个小于它的数后面。为什么?因为如果接在大于他的数后面,就不符合LIS的定义了(LIS要递增)。但如果替换一个比它小的数,又违反了 f f f 数组的定义( f f f 数组要最小)。综上,应该替换 f f f 数组从左往右第一个大于它的数。换句话说,它总是接在从左往右最后一个小于它的数后面,这样才能对 f f f