一个数的序列bi,当b1 < b2 < … < bS的时候,我们称这个序列是上升的。
对于给定的一个序列(a1, a2, …, aN),我们可以得到一些上升的子序列(ai1, ai2, …, aiK),这里1 <= i1 < i2 < … < iK <= N。
比如,对于序列(1, 7, 3, 5, 9, 4, 8),有它的一些上升子序列,如(1, 7), (3, 4, 8)等等。这些子序列中最长的长度是4,比如子序列(1, 3, 5, 8).
我们的任务,就是对于给定的序列,求出最长上升子序列的长度。(最长不上升子序列就是正相反呗。)
下面我们以最长上升子序列为例研究。
其他非递增(减)等一系列问题就是以此为基础啊,比较的时候改改条件就行啊!
看清题目要求!
递增和不下降是不一样的啊摔!
O(n²)算法
seq[i]表示输入的第i个元素,seqlen[i]表示以第i个元素为末位的最长子序列长度。
在seqlen数组里选出最长,就是最长子序列长度啊。
O(nlogn)算法
arr[i]表示输入的数组元素,ans[len]表示生成长度为len时子序列的末位元素,len表示序列长度。
如果arr数组的新元素比ans数组的所有元素都大,把这个元素放在ans数组的最后,子序列长度+1;
如果arr数组的新元素比ans数组的最大元素小,比ans数组的其他元素小,那就用新元素替换掉这个最大元素。比如len=2时,ans[2]={1,5};若ans[i]即新元素为3,那就替换掉5,使得ans[2]={1,3},以保证有更多元素加入到序列中来。
所以我们发现,我们插入这个数据是通过替换来实现的,因而我们可以通过二分查找快速找到要替换的元素,从而将时间复杂度降低到O(nlogn)。
来举个栗子~
假设存在一个序列arr[1..9] = 2 1 5 3 6 4 8 9 7,可以看出来它的LIS长度为5。
下面一步一步试着找出它。
我们定义一个序列ans,然后令 i = 1 to 9 逐个考察这个序列。
此外,我们用一个变量Len来记录现在最长算到多少了
首先,把arr[1]有序地放到ans里,令ans[1] = 2,就是说当只有一个数字2的时候,长度为1的LIS的最小末尾是2。这时Len=1。
然后,把arr[2]有序地放到ans里,令ans[1] = 1,就是说长度为1的LIS的最小末尾是1,arr[1]=2已经没用了,这时Len=1。
接着,arr[3] = 5,arr[3]>ans[1],所以令ans[1+1]=ans[2]=arr[3]=5,就是说长度为2的LIS的最小末尾是5,