[LeetCode-300]最长上升子序列

本文介绍了解决最长上升子序列问题的两种算法:一种使用二分查找优化的时间复杂度为O(N*logN),另一种为动态规划算法,时间复杂度为O(N*N)。通过实例演示了如何寻找给定数组中最长的上升子序列。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接:https://leetcode-cn.com/problems/longest-increasing-subsequence/


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

示例:
在这里插入图片描述
说明:

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

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


解题思路:

一、维护数组存储最长子序列

  • 当数组为空时或者当前值大于数组最后最后一个值,就直接插入
  • 当当前值小于数组中最后一个值时,就把当前值和数组中当前值大于的第一个值进行替换
  • 在查找数组中的当前值时,可以使用二分查找
/**
 * @author: hyl
 * @date: 2019/08/12
 **/
public class Que300 {

    //时间复杂度为O(N * logN),空间复杂度为O(N)
    public int lengthOfLIS(int[] nums) {

        if (nums == null || nums.length == 0){
            return 0;
        }

        int[] res = new int[nums.length];

        res[0] = nums[0];
        int index = 0;
        for (int i = 1; i < nums.length; i++) {

            if (nums[i] > res[index]){
                res[++index] = nums[i];
            }else{
                int indexNum = Arrays.binarySearch(res, 0, index, nums[i]);

                if (indexNum >= 0){
                    res[indexNum] = nums[i];
                }else{
                    //如果没找到,返回的是 -(mid + 1)
                    //需要看下二分查找的源码,这点有点坑,
                    //希望大家尽量可以使用自己写的,可以自定义自己返回的值
                    res[-indexNum-1] = nums[i];
                }
            }
        }

        return index+1;
    }

    public static void main(String[] args) {
        new Que300().lengthOfLIS(new int[]{10,9,2,5,3,7,101,18});
    }
}

总结:

  • 时间复杂度为O(N * logN),空间复杂度为O(N)
  • 如果不使用二分查找,则达不到O(N * logN),,只能退化成O(N *N)的算法

二、使用动态规划解决

  • dp[i]保存到nums[i]最长的上升子序列的长度
  • 每次求出最大的dp[i]即可
/**
 * @author: hyl
 * @date: 2019/08/12
 **/
public class Que300 {

    //dp求解
    //时间复杂度为O(N * N),空间复杂度为O(N)
    public int lengthOfLIS1(int[] nums) {

        if (nums == null || nums.length == 0){
            return 0;
        }

        int result = 1;
        int[] dp = new int[nums.length];

        for (int i = 0; i < nums.length; i++) {
            dp[i] = 1;
        }

        for (int i = 1; i < nums.length; i++) {
            for (int j = 0; j < i; j++) {

                if (nums[i] > nums[j]){
                    dp[i] = Math.max(dp[j] + 1 , dp[i]);
                }
            }
            result = Math.max(dp[i] , result);
        }
        

       return result;
    }

    public static void main(String[] args) {
        new Que300().lengthOfLIS(new int[]{10,9,2,5,3,7,101,18});
    }
}

代码地址:
https://github.com/Han-YLun/LeetCode/blob/master/Practice/src/Que300.java


文章为阿伦原创,如果文章有错的地方欢迎指正,大家互相交流。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值