[leetCode]最长的上升子序列

题目

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

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

示例:

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

说明:

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

动态规化

dp[i]代表以nums[i]结尾的数组最长子序列的长度

例如数组[10,9,2,5,3,7,101,18],假设已经知道了以下标Index结尾的子数组的最长子序列长度为x. 比如说index为6,也就是子数组sub=[10,9,2,5,3,7,101],这时候x = 4 (2,3,7,101)如果这时后加上一个数字18,这时求最长子序列的长度也就是要在子数组sub=[10,9,2,5,3,7,101]使用一个指针j从左向右遍历,如果sub[j] < 18那么就可以和18构成一个子序列,也就是dp[j] + 1,加上18后dp[i] (这里i为7)要取几种情况中的最大值,所以状态转移方程为:

d p [ i ] = m a x ( d p [ j ] + 1 ) 0 < = j < i , n u m s [ j ] < n u m s [ i ] dp[i] = max(dp[j] + 1) 0<=j <i ,nums[j] < nums[i] dp[i]=max(dp[j]+1)0<=j<inums[j]<nums[i]

class Solution {
    public int lengthOfLIS(int[] nums) {
        int n = nums.length;
        int[] dp = new int[n];
        int maxLen = 0;
        for (int i = 0; i < n; i++) {
            int len = 1;
            for (int j = 0; j < i; j++) {
                if (nums[j] < nums[i]) {
                    len = Math.max(len, dp[j] + 1); // 截止到j最长的长度+1
                }
            }
            dp[i] = len;
            maxLen = Math.max(maxLen, len);
        }
        return maxLen;
    } 
}

优化 使时间复杂度将为O(nlogn)

  数组nums的最长上升子序列的长度,不会超过其本身的长度n,因此创建一个长度为ndp数组,这个数组用来存放元素。
  从左向右遍历数组nums将元素插如dp数组中,由于要求最长上升子序列的长度因此要使dp数组中元素最多并保持上升状态。
  如果当前要加入的元素的插入位置在dp数组已加入元素的尾部,说明该元素比之前的元素都要大,比如dp=[2]插入元素为55>2因此插入在尾部dp=[2,5]
  如果当前元素没有比之前的元素都要大说明插入该元素不能使dp中序列的长度变长,比如说插入3, 此时 3<5。因此需要查询该元素在dp中的位置并替换该位置的元素,这样dp中的序列就会减小就能右更多的元素插入在尾部,也就是说dp[2,5]变为[2,3]
要知道元素的插入位置可以使用二分查找。

class Solution {
    public int lengthOfLIS(int[] nums) {
        int n = nums.length;
        int len = 0;
        int[] dp = new int[n];
        for (Integer num : nums ) {
            int index = Arrays.binarySearch(dp, 0,len, num);
            if (index < 0) {
                index = -index - 1;
            }
            dp[index] = num;
            if (index == len) {
                dp[index] = num;
                len++;
            }
        }
        return len;
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值