LeetCode 0300 -- 最长上升子序列

最长上升子序列

题目描述

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

示例:

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

说明:

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

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

解题思路

个人AC

维持一个子序列sequence,该序列中的元素是递增的,该序列实际承载元素的数量即为最长上升子序列的长度。遍历给定数组:

  • nums[i]大于sequence的最后一个元素时,直接将nums[i]置于该元素末尾,能够维护最长上升子序列的长度;
  • 否则,利用二分查找(时间复杂度为 O ( l o g n ) O(logn) O(logn))在sequence中寻找将要被nums[i]替换的元素的位置,即找到sequence中大于nums[i]的最小元素的位置。
class Solution {
    public int lengthOfLIS(int[] nums) {
        int n = nums.length;
        if (n < 2) return n;

        int[] sequence = new int[n];
        sequence[0] = nums[0];
        int maxLen = 1; // sequence的容量,即最长上升子序列的长度
        for (int i = 1; i < n; i++) {
            if (nums[i] > sequence[maxLen - 1]) { // 如果nums[i]大于sequence序列的最后一个元素,则直接放入其尾部即可
                sequence[maxLen++] = nums[i];
            } else { // 否则,使用二分法将nums[i]替换掉sequence序列中大于nums[i]的最小元素
                int pos = binarySearch(sequence, 0, maxLen, nums[i]);
                if (pos >= 0) {
                    sequence[pos] = nums[i];
                }
            }
        }
        return maxLen;
    }

    // 找到sequence[0, maxLen)中大于target的最小元素的位置
    private int binarySearch(int[] sequence, int left, int right, int target) {
        while (left < right) {
            int mid = left + (right - left) / 2;
            if (sequence[mid] == target) { // 如果target存在于sequence[0, maxLen)中,则返回-1,表明无需替换
                return -1;
            } else if (sequence[mid] < target) {
                left = mid + 1;
            } else {
                right = mid;
            }
        }
        return left;
    }
}

时间复杂度: O ( n l o g n ) O(nlogn) O(nlogn)

空间复杂度: O ( n ) O(n) O(n)

最优解

同上。

参考

图解一道腾讯笔试算法题:「最长上升子序列」

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值