[LeetCode] 300. Longest Increasing Subsequence

题:https://leetcode.com/problems/longest-increasing-subsequence/description/

题目

Given an unsorted array of integers, find the length of longest increasing subsequence.

Example:

Input: [10,9,2,5,3,7,101,18]
Output: 4 
Explanation: The longest increasing subsequence is [2,3,7,101], therefore the length is 4. 

Note:

  • There may be more than one LIS combination, it is only necessary for you to return the length.
  • Your algorithm should run in O(n2) complexity.
  • Follow up: Could you improve it to O(n log n) time complexity?

题目大意

找nums数值中,最长的 升序 字串,输出其长度。

思路

方法一

动态规划 O(n2)

状态dp[i]:以 nums[n] 结尾的序列的最长递增子序列长度。

状态转移方程:
dp[i] = max(1, dp[p] + 1 ),其中 i>p 且 nums[i] > nums[p];

若 下标 p < i,且 nums[p] < nums[i] ,也就是,从下标 i处,看前面 比nums[i] 小的元素 作为结尾的最长升序串L。由于 L存在多个,所以可以选取最大的L。

在遍历时候,从i-1 向前遍历,若 当前下标 j +1> 当前最大tmaxL,继续比较 下标j的元素,否则不用继续比较。因为此时 tmaxL 已经大于 前面元素的个数和,子串长度不可能大于tmaxL。

class Solution {
    public int lengthOfLIS(int[] nums) {
        int[] dp = new int[nums.length];
        for(int i = 0;i<nums.length;i++){
            int tsubmaxlen = 0;
            for(int j = i-1 ;j>=0 &&j+1>tsubmaxlen ;j--){
                if(nums[j]<nums[i] && tsubmaxlen<dp[j])
                    tsubmaxlen = dp[j];
            }
            dp[i] = Math.max(1,tsubmaxlen+1);
        }
        int maxlen = 0;
        for(int i= 0 ;i< nums.length;i++)
            if(maxlen<dp[i])
                maxlen = dp[i];
        return maxlen;
    }
}

由于 tsubmaxlen >=0 所以 j>=0 &&j+1>tsubmaxlen 可简化为 j>=tsubmaxlen。

class Solution {
    public int lengthOfLIS(int[] nums) {
        int[] dp = new int[nums.length];
        for(int i = 0;i<nums.length;i++){
            int tsubmaxlen = 0;
            for(int j = i-1 ;j>=tsubmaxlen ;j--){
                if(nums[j]<nums[i] && tsubmaxlen<dp[j])
                    tsubmaxlen = dp[j];
            }
            dp[i] = Math.max(1,tsubmaxlen+1);
        }
        int maxlen = 0;
        for(int i= 0 ;i< nums.length;i++)
            if(maxlen<dp[i])
                maxlen = dp[i];
        return maxlen;
    }
}

方法二

动态规划 O(n log n)

状态tails[i]:存储长度为 i + 1 的最长递增子序列的最后一个元素。

状态转移

对于一个元素 x,

  • 如果它大于 tails 数组所有的值,那么把它添加到 tails 后面,表示最长递增子序列长度加 1;
  • 如果 tails[i-1] < x <= tails[i],那么更新 tails[i] = x。

例如对于数组 [4,3,6,5],有:

tails      len      num
[]         0        4
[4]        1        3
[3]        1        6
[3,6]      2        5
[3,5]      2        null

可以看出 tails 数组保持有序,因此在查找 Si 位于 tails 数组的位置时就可以使用二分查找。

class Solution {
    public int binarySearch(int []tails,int len,int key){
        int l = 0,h = len-1;
        while(l<=h){
            int m = l + (h - l)/2;
            if(tails[m] > key){
                h = m -1;
            }
            else if(tails[m] < key){
                l = m + 1;
            }
            else    return m;
        }
        return l;
    }
    
    public int lengthOfLIS(int[] nums) {
        int[] tails = new int[nums.length];
        int len = 0;
        for(int i = 0 ;i < nums.length; i++){
            int index = binarySearch(tails,len,nums[i]);
            tails[index] = nums[i];
            if(index == len) len++;
        }
        return len;
        
    }
}

猜你喜欢

转载自blog.csdn.net/u013383813/article/details/83027751