zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    Flask目录结构
    RHSA-2019:1880-低危: curl 安全和BUG修复更新 及 RHSA-2019:1884-中危: libssh2 安全更新
    ELK+Logback进行业务日志分析查看
    Maven编译过程中出现的问题
    Zabbix监控服务器磁盘I/O
    创建readonly只读用户脚本
    Zabbix监控多个JVM进程
    redis命令
    docker配置Nginx
    docker基本命令
  • 原文地址:https://www.cnblogs.com/joker1937/p/12812892.html
Copyright © 2011-2022 走看看