leetcode300.最长上升子序列

Posted Joker1937

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了leetcode300.最长上升子序列相关的知识,希望对你有一定的参考价值。

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

示例:

输入: [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.最长上升子序列的主要内容,如果未能解决你的问题,请参考以下文章

leetcode300 最长上升子序列(Medium)

Leetcode-300. 最长上升子序列

Leetcode 300.最长上升子序列

leetcode-300最长上升子序列

leetcode300.最长上升子序列

leetcode 300. 最长上升子序列