[leetbook中级算法-动态规划(java解法)]LC最长上升子序列

leetbook:中级算法

类型:动态规划

题目名:最长上升子序列
原题URL:https://leetcode-cn.com/leetbook/read/top-interview-questions-medium/xwhvq3/

题目描述

给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。

子序列是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。

示例 1:

输入:nums = [10,9,2,5,3,7,101,18]
输出:4
解释:最长递增子序列是 [2,3,7,101],因此长度为 4 。

示例 2:

输入:nums = [0,1,0,3,2,3]
输出:4

示例 3:

输入:nums = [7,7,7,7,7,7,7]
输出:1
限制
  • 1 <= nums.length <= 2500
  • -104 <= nums[i] <= 104

进阶:

  • 你可以设计时间复杂度为 O(n2) 的解决方案吗?
  • 你能将算法的时间复杂度降低到 O(n log(n)) 吗?
解题思路

1.动态规划,dp[i]表示0~i位置的最长上升子序列的个数

2.循环枚举,如果当前位置比循环位置大,就加入到当前位置的最长子序列中

3.每次该位置的最长子序列长度要做一次记录并且与最长的比较

4.可以进行二分优化(二分得比较丑陋请见谅)

解题代码
class Solution {
    public int lengthOfLIS(int[] nums) {
        if(nums==null||nums.length==0) return 0;
        //i,j位置的最长子序列个数
        int len = nums.length;
        int[] dp = new int[len];
        //初始化
        for (int i = 0; i < len; i++) {
            dp[i] =1;
        }
        //记录最大值,默认值1
        int max = 1;
        //定住i的位置,从0-i开始搜索,如果当前位置可以加入到最大子序列,就将其加入
        for (int i = 1; i < len; i++) {
            //如果当前值比j位置要大,那就往后面加
            for (int j = 0; j < i; j++) {
                if(nums[j]<nums[i]) {
                    dp[i] = Math.max(dp[j]+1,dp[i]);
                }
            }
            //找到每一个位置的最大子序列,来进行比较
            max = Math.max(max,dp[i]);
        }
        return max;
    }
}

优化代码

public class Solution {
    public int lengthOfLIS(int[] nums) {
        if(nums==null||nums.length==0) return 0;
        int len = nums.length;
        //思路,,用一个数组来存储最长子序列
        int[] dp = new int[len];
        int idx = 0;
        dp[0] = nums[0];
        int start = 0;
        int end = idx;
        int mid = 0;
        for(int i =1;i<len;i++) {
            //如果当前数字大于最长子序列的最大值,那么直接加在末尾
            if(nums[i]>dp[idx]) dp[++idx] = nums[i];
            else if(nums[i]<dp[0]) dp[0] = nums[i];
            else {
                start = 0;
                end = idx;
                //如果没有的话,就在最长子序列中找到他应该在的位置
                //因为是升序的,,所以可以使用二分查找
                while(start<=end) {
                    mid = start+(end-start)/2;
                    if(dp[mid]>=nums[i]) {
                        if(mid-1<0||dp[mid-1]<nums[i]) {
                            dp[mid] = nums[i];
                            break;
                        }
                        else end = mid-1;
                    }else {
                        start = mid+1;
                    }
                }
            }
        }
        return idx+1;

    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值