[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 }