LeetCode300动态规划问题分析

@LeetCode300:给定一个无序的整数数组,找到其中最长上升子序列的长度。写自定义目录标题)

问题

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

示例:

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

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

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/longest-increasing-subsequence
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。。

问题分析

该问题是一个最优解问题,很容易想到使用动态规划的方法完成。

  1. 分析问题结构:该问题求解给定数组的最长递增序列串的长度,数组[10,9,2,5,3,7,101,18]中,LIS序列中每个元素不一定是紧挨着分布,可能分布离散;假设我们找到了前4个元素的LIS是2(2,5构成LIS),对于第5个元素3,不可能和2,5继续构成递增序列,因此如果满足nums[i+1]>nums[i],则前i+1个元素有可能构成LIS;假如前i个元素构成的LIS中最后一个元素刚好小于nums[i+1],则必能构成新的LIS。
  2. 寻找递归关系:假设访问前i个元素时,第i个元素恰好是其LIS的最大值,那么在访问第i+1个元素时可以根据nums[i+1]和nums[i]的值关系,确定前i+1个元素的LIS;由此可以找到前i个元素的LIS长度和前i+1个元素的LIS间的递归关系。
  3. 分别计算最优值:用bp[i]记录第i个元素为LIS中最大元素时的LIS长度,初始时,设置bp[i]中每个值默认为1(每个元素的bp值肯定不会小于1),遍历nums[i],寻找以 nums[i] 结尾的最长上升子序列;通过上边的分析可知,第nums[i]与0-i之间的j处的num[j]有关,即dp[i] = MAX{dp[i],dp[j]+1}。最后,整个数组的最长上升子序列,即所有 dp[i] 中的最大值。

参考代码

public int lengthOfLIS3(int[] nums) {//动态规划解法,复杂的O(n²)
		if(nums.length < 2)  return nums.length;  
        int dp[] = new int[nums.length];
        Arrays.fill(dp,1);
        int maxLen = 1;//如果数组元素个数不为0,则LIS长度至少是1
        
        for(int i = 0; i < nums.length; i++) {
            int max = 1;//前i元素中LIS最大值
            
            for(int j = 0; j < i; j++) {//查找以a[i]为结尾的LIS长度
                if(nums[i] > nums[j]) { //有可能存在LIS
                	//nums[j]为LIS最大值的长度+1,与前j个中LIS最大值max做比较
                    max = Math.max(dp[j] + 1, max );//取最大
                }
            }
            dp[i] = max;//更新前i个元素的LIS的最大值
            
            if(dp[i] > maxLen) {
                maxLen = dp[i];
            }
        }

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值