【动归】B011_最长上升子序列(dp | 贪心 + 二分)

一、题目描述


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

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?

二、题解

方法一:dp

能找到思路了!

  • 定义状态:dp[i] 表示下标至 i 为止的最长上升子序列。
  • 思考状态转移方程:对于每一个元素,都要在区间 [ j , i ] [j, i] 检查 LIS 的长度。
    • d p [ i ] = m a x ( d p [ i ] ,   d p [ j ] + 1 ) dp[i] = max(dp[i],\ dp[j]+1)
  • 思考初始化:对于长度大于 0 的子序列,其最短的上升子序列为自身。
    • d p [ 0... N ] = 1 dp[0...N] = 1
  • 思考输出 m a x ( d p [ i . . . N ] ) max(dp[i...N])

如果你不理解最优子结构是 d p [ i ] = m a x ( d p [ i ] ,   d p [ i 1 ] + 1 ) dp[i] = max(dp[i],\ dp[i-1] + 1) ,可以模拟一下这段样例: [ 1 , 3 , 6 , 7 , 9 , 4 , 10 , 5 , 6 ] [1,3,6,7,9,4,10,5,6] ,答案是 6.

public int lengthOfLIS(int[] nums) {
  final int N = nums.length;
  int[] dp = new int[N];
  Arrays.fill(dp, 1);

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

复杂度分析

  • 时间复杂度: O ( N 2 ) O(N^2)
  • 空间复杂度: O ( N ) O(N)

方法二:二分查找优化(没想道)

遍历原数组 nums,将每个元素按照规则二分插入数组 LIS 中,LIS 中的元素都是升序排列的。

  • 如果 LIS 中的元素比我大,我就覆盖 LIS 中第一个比我大的元素。
    • 可用二分。
  • 否则,加到 LIS 的后面。
public int lengthOfLIS1(int[] nums) {
  final int N = nums.length;
  if (N < 2)  return N;

  int[] LIS = new int[N];
  LIS[0] = nums[0];
  int p = 1;
  
  for (int i = 1; i < N; i++) {
    if (nums[i] > LIS[p]) {
      LIS[++p] = nums[i];
      continue;
    }
    int l = 0, r = p;
    while (l < r) {
      int mid = l + ((r - l) >>> 1);
      if (nums[i] > LIS[mid]) l = mid + 1;
      else r = mid;
    }
    LIS[l] = nums[i];
  }
  return p;
}

复杂度分析

  • 时间复杂度: O ( N l o g N ) O(N logN)
  • 空间复杂度: O ( N ) O(N)
发布了461 篇原创文章 · 获赞 102 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/qq_43539599/article/details/104664797