最长递增子序列
简介:
今天的算法课上学习了动态规划(Dynamic programming),简单的来说,动态规划解决问题就是在解决问题的过程中通过不断的解决一些小问题最终解决大问题,并且与分治算法的区别是它并不要求小问题要比大问题规模小很多,其中LIS问题是我们主要学习的例子:
LIS问题
给定一个数的序列a1,a2...an
找到最长的递增子序列
解法:
- 动态规划O(n*n):
动态规划方程:
L(j) = 1+max{L(i):i < j}
具体过程:
L[n]是一个存储序列长度的数组,初始化为1;
对于序列中的每一个值来说,遍历坐标小于它的值,观察其序列长度+1是否大于他本身的序列长度。 这样我们就可以得到每一个值得序列长度,最后找到数组L中的最大值即可,很容易看出其复杂度为O(n*n);
如果我们想要得到最长子序列,只需添加prev[j]存储前驱结点即可。 - 改进O(n*logn)
我们考虑:在动态规划中的内部循环,我们采用遍历的方式查询,是否可以采用其他方式使其复杂度降低?
在计算每一个L(j)时,都要找出最大的L(i) (i < j);
我们采用一个B序列,来记录最大递增子序列的最末元素,B[L(j)] = aj;
对于B采用二分查找,找到使得B中小于目标值的最大值的下一个为目标。
举个例子:a[1-6] = {2, 1, 5, 8 , 9 , 7}
初始化B[6], len = 1, B[1] = 2;
a[2] < B[1] B[1] = 1 len = 1;
a[3] > B[1] B[2] = 5 len = 2;
a[4] > B[2] B[3] = 8 len = 3;
a[5] > B[3] B[4] = 9 len = 4;
a[6] < B[3]&a[6] > B[2] B[3] = 7 len = 4;
len即为最长子序列的长度,而1,5,7, 9 并不是一个子序列,只不过是对应长度子序列的最末元素的最小值。