最长连续递增子序列问题

最长连续递增子序列问题:

给定一个长度为N的数组,给定一个长度为N的数组,找出一个最长的单调自增子序列(不一定连续,但是顺序不能乱)。例如:给定一个长度为6的数组A{5, 6, 7, 1, 2,8},则其最长的单调递增子序列为{5,6,7,8},长度为4。

动态规划做法(时间复杂度O(N^2))

假设我们定义一个大小为n的数组a,每个元素的值分别为a[0],a[1],....,a[n-1]。

我们将dp[i]表示为以下标为i结尾的最长递增子序列长度,那么dp[i]的值就等于从数组开始位置到i-1位置处找到的最大的dp[j](0<j<i且a[i]≥a[j]),然后dp[i] = dp[j] + 1。

 

算法流程:

从数组头到尾遍历每个位置i,根据i往前找所有满足a[i]≥a[j]要求的j,且找到对应的dp[j]最大的哪一个j位置。遍历完整个数组之后,得到整个dp数组中最大的那个dp[j]便是最长递增子序列的长度。

 

例子:

最长连续递增子序列问题

 

时间复杂度:

由于要遍历一遍数组,而且遍历到每个位置i时还要往前找到最大的dp[j](0<j<i且a[i]≥a[j]),因此时间复杂度为O(N^2)。

 

 

核心代码:

最长连续递增子序列问题

 

 

利用二分法(时间复杂度为O(NlogN))

动态规划的方法时间复杂度稍高,我们也可以利用二分法得出最长递增子序列的长度。

 

算法流程:

定义数组a = {5,6,7,1,2,8}

定义一个变长的临时数组tempArr,要求该数组的元素从小到大排序。

 

1)遍历到5,数组tempArr为空,直接加入tempArr中。

最长连续递增子序列问题

2)遍历到6,由于6大于数组中最后一个元素5,6直接加到数组后面。

最长连续递增子序列问题

3)遍历到7,由于7大于数组中最后一个元素6,7直接加到数组后面。

最长连续递增子序列问题

4)遍历到1,1小于数组中最后一个元素7,此时要在tempArr数组中找到>1最左边的元素,找到为5,然后替换掉。因为既然可以以5来往后找最长连续递增子序列,那为什么不拿1来找呢?所以这就是算法的核心

最长连续递增子序列问题

5)遍历到2,同样由于2<7,所以找到>2最左边的数,为6,替换,理由同上。

最长连续递增子序列问题

6)遍历到8,由于8>7,所以直接插入。

最长连续递增子序列问题

算法结束,最长连续递增子序列就是此时tempArr数组中的长度,为4.

 

整个过程如下图所示

最长连续递增子序列问题

可以看出,整个算法的核心为遍历每一个数k,然后判断k和tempArr数组中最后一个数谁大,如果k大于或者等于tempArr数组中最后一个数,则直接插入tempArr中,如果k小于tempArr数组中最后一个数,则在tempArr中找到>k的最左边的那个数,然后用k替换掉。

 

时间复杂度

那么在元素递增数组tempArr中找>k最左边的那个数的时候,便可以使用二分法加速该过程。因此时间复杂度为O(NlogN)。

 

核心代码

最长连续递增子序列问题