最长上升子序列问题:
给定n个整数A1,A2,…,An,按从左到右的顺序选出尽量多的整数,组成一个上升子序列(子序列可以理解为:删除0个或多个数,其他数的顺序不变)。例如序列1,6,2,3,7,5,可以选出上升子序列1,2,3,5,也可以1,6,7,但前者更长。选出的上升子序列中相邻元素不能相同。
【分析】
设d(i)为以i结尾的最长上升子序列列的长度,则d(i)=max{0,d(j)|j<i,Aj<Ai}+1, 最终答案是max{d(i)}。如果LIS中的相邻元素可以相等,把小于号改成等于号即可。上述算法的时间复杂度为O(n*n);
不仅如此,还可以将算法复杂度调节到O(nlogn)
假设存在一个序列d[1..9] = 2 1 5 3 6 4 8 9 7,可以看出来它的LIS长度为5。n
下面一步一步试着找出它。
我们定义一个序列B,然后令 i = 1 to 9 逐个考察这个序列。
此外,我们用一个变量Len来记录现在最长算到多少了
首先,把d[1]有序地放到B里,令B[1] = 2,就是说当只有1一个数字2的时候,长度为1的LIS的最小末尾是2。这时Len=1
然后,把d[2]有序地放到B里,令B[1] = 1,就是说长度为1的LIS的最小末尾是1,d[1]=2已经没用了,很容易理解吧。这时Len=1
接着,d[3] = 5,d[3]>B[1],所以令B[1+1]=B[2]=d[3]=5,就是说长度为2的LIS的最小末尾是5,很容易理解吧。这时候B[1..2] = 1, 5,Len=2
再来,d[4] = 3,它正好加在1,5之间,放在1的位置显然不合适,因为1小于3,长度为1的LIS最小末尾应该是1,这样很容易推知,长度为2的LIS最小末尾是3,于是可以把5淘汰掉,这时候B[1..2] = 1, 3,Len = 2
继续,d[5] = 6,它在3后面,因为B[2] = 3, 而6在3后面,于是很容易可以推知B[3] = 6, 这时B[1..3] = 1, 3, 6,还是很容易理解吧? Len = 3 了噢。
第6个, d[6] = 4,你看它在3和6之间,于是我们就可以把6替换掉,得到B[3] = 4。B[1..3] = 1, 3, 4, Len继续等于3
第7个, d[7] = 8,它很大,比4大,嗯。于是B[4] = 8。Len变成4了
第8个, d[8] = 9,得到B[5] = 9,嗯。Len继续增大,到5了。
最后一个, d[9] = 7,它在B[3] = 4和B[4] = 8之间,所以我们知道,最新的B[4] =7,B[1..5] = 1, 3, 4, 7, 9,Len = 5。
于是我们知道了LIS的长度为5。
!!!!! 注意。这个1,3,4,7,9不是LIS,它只是存储的对应长度LIS的最小末尾。
咱们可以发现,1,3,4,7,9严格按照大小顺序排列,所以查找一个数使用二分法去查找
例题:
hdu 1950 Bridging signals
http://acm.hdu.edu.cn/showproblem.php?pid=1950
给定两个子序列A和B,求长度的最大子序列;
例如1,5,2,6,8,7和2,3,5,6,9,8,4
最长公共子序列为5,6,8或者2,6,8
【分析】
设d(i,j)为A1,A2,…,Ai和B1,B2,…,Bj的LCS长度,则当A(i)=B(j)时,d(i,j)=d(i-1,j-1)+1,
否则d(i,j)=max{d(i-1,j),d(i,j-1)},时间复杂度为O(nm),其中n和m分别为序列A和序列B的长度。