leetcode hot 100-300. 最长上升子序列

300. 最长上升子序列

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

示例:

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

说明:

可能会有多种最长上升子序列的组合,你只需要输出对应的长度即可。
你算法的时间复杂度应该为 O(n2) 。

进阶: 你能将算法的时间复杂度降低到 O(n log n) 吗?

思路一:动态规划

思路参考:动态规划 ---- 最长不下降子序列(Longest Increasing Sequence, LIS)

dp[i]表示以nums[i]为结尾的最长上升子序列的长度
计算dp[i]的过程为,遍历[0, i-1]之间的元素 nums[j] ,判断能否把 nums[i] 加入到以 nums[j] 元素结尾的最长上升子序列的尾部,加入依据是仍然维持是一个上升子序列。即判断是否 nums[i] > nums[j]
如果可以则判断能否能把 dp[i] 增大,即能否比 nums[i] 当前所在的最长上升子序列长度更长,如果可以(即如果 dp[j] + 1 > dp[i]),把nums[i]元素加入到 nums[j] 所在的上升子序列中,则dp[i] = dp[j] + 1
边界情况分析,每个元素都可以以当前元素为一个上升子序列,所以显然每个 dp[i] 最小为1,所以dp[i]的初值为 1 
 1 class Solution {
 2     public int lengthOfLIS(int[] nums) {
 3         if(nums == null || nums.length == 0){
 4             return 0;
 5         }
 6 
 7         // 边界情况分析,每个元素都可以以当前元素为一个上升子序列,所以显然每个dp[i]最小为1
 8         int len = nums.length;
 9         int[] dp = new int[len];
10         int max = 1;
11         dp[0] = 1;
12         for(int i = 1; i < len; i++){
13             dp[i] = 1;
14             for(int j = 0; j < i; j++){
15                     // 如果可以维持一个上升序列且时最长上升序列更长,则更新dp[i]
16                     if(nums[i] > nums[j] && dp[j] + 1 > dp[i]){
17                     dp[i] = dp[j] + 1;
18                 }
19             }
20             max = Math.max(dp[i], max);
21         }
22         return max;
23     }
24 }

leetcode 执行用时:15 ms > 44.16%, 内存消耗:36.3 MB > 95.15%

复杂度分析:

时间复杂度:O(n2)。双循环,所以时间复杂度为O(n2)。

空间复杂度:O(n)。需要一个大小为 n 辅助数组dp[], 所以空间复杂度为O(n)。

原文地址:https://www.cnblogs.com/hi3254014978/p/13875391.html