最长连续子序列偏移_最长连续递增子序列问题

最长递增子序列问题:

给定一个长度为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

算法流程:

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

例子:

ddf353650fd0be5b0383617c659e6994.png

时间复杂度:

由于要遍历一遍数组,而且遍历到每个位置i时还要往前找到最大的dp[j](0

核心代码:

34f8a62ef96710d535a1da0b4ff1453b.png

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

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

算法流程:

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

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

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

f74931b3d9c4afc57f4798225e976df3.png

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

6597701cf91c10cbbbd540710aec7535.png

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

9d2df34fe13f625100df6d2a77362f53.png

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

f481c78bf4c273b66a44b6f979d5021a.png

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

568410c342023ee664efd895cce8a355.png

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

ba0a6ece4b22b0d5c9654ee9a8f1a479.png

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

整个过程如下图所示

e871d88c95a11b7025fb03ad3f5c3365.png

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

时间复杂度

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

核心代码

7d593db91c62398d6a9561f18e61ebe6.png
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值