[LeetCode] 673. Number of Longest Increasing Subsequence

Given an integer array nums, return the number of longest increasing subsequences. 

Example 1:

Input: nums = [1,3,5,4,7]
Output: 2
Explanation: The two longest increasing subsequences are [1, 3, 4, 7] and [1, 3, 5, 7].

Example 2:

Input: nums = [2,2,2,2,2]
Output: 5
Explanation: The length of longest continuous increasing subsequence is 1, and there are 5 subsequences' length is 1, so output 5.

Constraints:

  • 1 <= nums.length <= 2000
  • -106 <= nums[i] <= 106

最长递增子序列的个数。

给定一个未排序的整数数组 nums , 返回最长递增子序列的个数 。

注意 这个数列必须是 严格 递增的。

思路还是动态规划。做这个题之前建议先熟悉一下300题的动态规划的做法。对于这道题,我们需要两个额外数组来记录一些信息,长度都和 input 数组一样,一个是 DP 数组,表示以 nums[i] 结尾的最长递增子数组的长度;一个是 counter 数组,表示以 nums[i] 结尾的最长递增子序列的数量。其中 DP 数组的初始化和更新方法和300题类似。对于在 0 - i 之间的某个下标 j 而言,如果 nums[j] < nums[i] 那么dp[i] 可以被更新成 dp[j] + 1;但是 counter[i] 怎么更新呢?注意因为 counter[i] 的定义是以 nums[i] 为结尾的最长子序列的个数,因为 nums[i] > nums[j] 所以如果把 nums[i] 加到一个以 nums[j] 为结尾的递增子序列上,这个新的子序列一定也能维持递增,所以 counter[i] = counter[j]。

但是如果 dp[j] + 1 == dp[i],意思是如果以 nums[j] 结尾的子序列的长度 + 1 = 以 nums[i] 为结尾的子序列的长度的话,counter[i] 的数量要 += counter[j]。举个例子,比如现在有一个以 5 结尾的子数组,他的长度是x,现在又发现一个以4为结尾的子数组,他的长度是 x - 1的话,这样后者就能插入前者,使得以 5 为结尾的子数组的个数 = x + x - 1。最后记录一个变量 max,记录全局范围内最大的 DP 值。

再次遍历 DP 数组,如果 dp[i] = max,则把 counter[i] 累加到结果里面。因为 dp[i] 是最长的递增子序列的长度,所以 counter[i] 是这个最长长度子序列的个数。

时间O(n^2)

空间O(n)

Java实现

 1 class Solution {
 2     public int findNumberOfLIS(int[] nums) {
 3         // corner case
 4         if (nums == null || nums.length == 0) {
 5             return 0;
 6         }
 7 
 8         // normal case
 9         int n = nums.length;
10         // 以nums[i]结尾的最长递增子序列的长度
11         int[] dp = new int[n];
12         // 以nums[i]结尾的最长递增子序列的个数
13         int[] counter = new int[n];
14         Arrays.fill(dp, 1);
15         Arrays.fill(counter, 1);
16         // 全局最长递增子序列的长度
17         int max = 0;
18         for (int i = 0; i < n; i++) {
19             for (int j = 0; j < i; j++) {
20                 if (nums[j] < nums[i]) {
21                     if (dp[i] < dp[j] + 1) {
22                         // dp[i] = Math.max(dp[i], dp[j] + 1);
23                         dp[i] = dp[j] + 1;
24                         counter[i] = counter[j];
25                     } else if (dp[i] == dp[j] + 1) {
26                         counter[i] += counter[j];
27                     }
28                 }
29             }
30             max = Math.max(max, dp[i]);
31         }
32 
33         int res = 0;
34         for (int i = 0; i < n; i++) {
35             // 只有dp值 = 最长递增子序列的长度,才把个数累加到结果
36             if (dp[i] == max) {
37                 res += counter[i];
38             }
39         }
40         return res;
41     }
42 }

 

LeetCode 题目总结

posted @ 2020-11-02 07:36  CNoodle  阅读(197)  评论(0编辑  收藏  举报