Leetcode 300- 最长上升子序列(LIS)

题目转载自Leetcode
给定一个无序的整数数组,找到其中最长上升子序列的长度。

示例:

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

可能会有多种最长上升子序列的组合,你只需要输出对应的长度即可。
你算法的时间复杂度应该为 O(n2) 。
进阶: 你能将算法的时间复杂度降低到 O(n log n) 吗?

题解

题解转载自labuladong
一、动态规划解法
本文定义dp数组:dp[i] 表示以 nums[i] 这个数结尾的最长递增子序列的长度。
根据这个定义,可以推出 base case:dp[i] 初始值为 1,因为以 nums[i] 结尾的最长递增子序列起码要包含它自己。

举两个例子:
在这里插入图片描述
根据这个定义,我们的最终结果(子序列的最大长度)应该是 dp 数组中的最大值。

int res = 0;
for (int i = 0; i < dp.size(); i++) {
    res = Math.max(res, dp[i]);
}
return res;

那么状态转移方程是怎样的?假设我们已经知道了 dp[0…4] 的所有结果,我们如何通过这些已知结果推出 dp[5] 呢?
在这里插入图片描述

根据刚才我们对 dp 数组的定义,现在想求 dp[5] 的值,也就是想求以 nums[5] 为结尾的最长递增子序列。nums[5] = 3,既然是递增子序列,我们只要找到前面那些结尾比 3 小的子序列,然后把 3 接到最后,就可以形成一个新的递增子序列,而且这个新的子序列长度加一。
显然,可能形成很多种新的子序列,但是我们只选择最长的那一个,把最长子序列的长度作为 dp[5] 的值即可。

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

完整版代码实现

class Solution {
    public int lengthOfLIS(int[] nums) {
        //dp[i]代表以nums[i]结尾的LIS的长度
        int[] dp = new int[nums.length];
        //dp[i]最小值为1,因为以nums[i]结尾的LIS至少包含其自身
        Arrays.fill(dp,1);
        int res=0;

        //获得dp[i]数组
        for(int i=0;i<dp.length;i++){
            for(int j=i;j<dp.length;j++){
                //如果nums[j]>nums[i],代表nums[j]可以接在以nums[i]结尾的LIS后
                if(nums[j]>nums[i]){
                    //找到nums[j]结尾的最长的递增子序列
                    dp[j]=Math.max(dp[j],dp[i]+1);
                }
            }
        }
        
        //找到dp数组中的最大值
        for(int i=0;i<dp.length;i++){
            res=Math.max(res,dp[i]);
        }

        return res;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值