码迷,mamicode.com
首页 > 其他好文 > 详细

leetcode300.最长上升子序列

时间:2020-05-01 12:34:36      阅读:52      评论:0      收藏:0      [点我收藏+]

标签:length   思路   子序列   遍历数组   算法   style   循环   最长上升子序列   ++   

给定一个无序的整数数组,找到其中最长上升子序列的长度。

示例:

输入: [10,9,2,5,3,7,101,18]
输出: 4
解释: 最长的上升子序列是 [2,3,7,101],它的长度是 4。

说明:

可能会有多种最长上升子序列的组合,你只需要输出对应的长度即可。
你算法的时间复杂度应该为 O(n2) 。

进阶:

你能将算法的时间复杂度降低到 O(n log n) 吗?

思路:维护一个tail数组,tail[k]表示长度为k+1的最长上升子序列的尾部元素例如:原数组为[10,9,2,5,3,7,21,18]

tail每轮更新情况:
i=0时:tails:[10]
i=1时:tails:[9]
i=2时:tails:[2]
i=3时:tails:[2,5]
i=4时:tails:[2,3]
i=5时:tails:[2,3,7]
i=6时:tails:[2,3,7,21]
i=7时:tails:[2,3,7,18]
每次都保持尾部元素最小。
如果再加一个5元素,则通过二分法找到第一个大于5的元素7,将7替换成5。
如果再加一个9元素,则通过二分法找到第一个大于9的元素18,将18替换成9。如此下去。
因为题目要求将算法复杂度降到nlogn,而遍历数组中的数字是免不了的,只能优化tail的更新过程,我们可以看到tails中的元素必然是
有序的,所以显然我们可以通过二分查找快速定位到需要替换的元素位置。代码如下:
int lengthOfLIS(vector<int>& nums) {
    vector<int> tails(nums.size());
    int res = 0;
    for(int num : nums) {
        int i = 0, j = res;
        //while循环退出条件:i == j
        while(i < j) {
            int mid = (i + j) / 2;
            if(num > tails[mid]) i = mid + 1;
            else j = mid; //此处不能是mid-1
        }

        tails[i] = num;
        //res == j表示j一直没有前移,一直指向最末尾,表示tail中所有数字都小于num,直接加到tails末尾
        if(res == j) res++;
    }
    return res;
}

 

leetcode300.最长上升子序列

标签:length   思路   子序列   遍历数组   算法   style   循环   最长上升子序列   ++   

原文地址:https://www.cnblogs.com/joker1937/p/12812892.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!