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
最长递增子序列的个数。题意不难理解,思路还是动态规划。
做这个题之前建议先熟悉一下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 int max = 0; 17 for (int i = 0; i < n; i++) { 18 for (int j = 0; j < i; j++) { 19 if (nums[j] < nums[i]) { 20 if (dp[j] + 1 > dp[i]) { 21 dp[i] = Math.max(dp[i], dp[j] + 1); 22 counter[i] = counter[j]; 23 } else if (dp[j] + 1 == dp[i]) { 24 counter[i] += counter[j]; 25 } 26 } 27 } 28 max = Math.max(max, dp[i]); 29 } 30 int res = 0; 31 for (int i = 0; i < n; i++) { 32 if (dp[i] == max) { 33 res += counter[i]; 34 } 35 } 36 return res; 37 } 38 }