300-最长递增子序列(最长递增子序列)

题目

给你一个整数数组 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

题解一(动态规划)

class Solution {
    public int lengthOfLIS(int[] nums) {
        if(nums.length==0||nums==null){
            return 0;
        }
        int[] dp=new int[nums.length];
        dp[0]=1;
        Arrays.fill(dp,1);//注意!
        int ans=dp[0];
        for(int i=0;i<nums.length;i++){
            for(int j=0;j<i;j++){
                if(nums[j]<nums[i]){
                    dp[i]=Math.max(dp[j]+1,dp[i]);//遍历j,就可以得到最大的dp[j],由于j前面的dp可能大于j,所以还需要比较dp[j]+1和dp[i].
                }
            }
            ans=Math.max(ans,dp[i]);//得到dp[i]数组中的最大值
        }
        return ans;
    }
}

笔记:

  1. 状态转移方程:dp[i]表示在第i个元素之前的最长递增子序列的长度,dp[i]=max(dp[j])+1,其中0<=j<i且num[j]<num[i]
  2. 时间复杂度是O(N^2)
  3. 因为转移方程和dp[j]相关,所以如果不预先置1,会影响输出结果。

题解二(动态规划+二分查找 *)

class Solution {
    public int lengthOfLIS(int[] nums) {
        if(nums.length<=1){
            return nums.length;
        }
        int[] tails=new int[nums.length];
        tails[0]=nums[0];
        int res=0;
        for(int num:nums){
            int i=0,j=res;
            while(i<j){
                int mid=i+(j-i)/2;
                if(tails[mid]<num)i=mid+1;
                else j=mid;
            }
            tails[i]=num;
            if(i==res)res++;
        }
        return res;
    }
}

笔记:

  1. 思路:

    维护一个tails[]数组,tails[i]表示长度为i+1的子序列尾部的值,遍历原nums[]数组,

    若第k个数比tails[i]小,大于tails[i-1],则用nums[k]替换掉tails[i],若第k个数大于tails[i],则append在tails[i]尾部,len+1.

  2. 在tails里搜寻时,因为tails是有序数组,所以使用二分搜索.

  3. tails[k]的值代表长度为 k+1子序列的尾部元素值。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

codrab

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值