LeetCode-673. 最长递增子序列的个数
题目来源
题目详情
给定一个未排序的整数数组 nums
, 返回最长递增子序列的个数 。
注意 这个数列必须是 严格 递增的。
示例 1:
输入: [1,3,5,4,7]
输出: 2
解释: 有两个最长递增子序列,分别是 [1, 3, 4, 7] 和[1, 3, 5, 7]。
示例 2:
输入: [2,2,2,2,2]
输出: 5
解释: 最长递增子序列的长度是1,并且存在5个子序列的长度为1,因此输出5。
提示:
1 <= nums.length <= 2000
-106 <= nums[i] <= 106
相似题目
题号 | 题目 | 标签 |
---|---|---|
673 | 最长递增子序列的个数 | 子序列;递增 |
300 | 最长上升子序列 | 子序列;递增 |
674 | 最长连续递增序列 | 子序列;递增 |
354 | 俄罗斯套娃信封问题 | 子序列;递增 |
题解分析
解法一:动态规划
- 本题是典型的动态规划题目,而且本题与最长上升子序列极度相似,但是本题有一些不同点,那就是它不是要求最长递增子序列的长度,而是要求最长递增子序列的个数。
- 我们知道,单靠最长上升子序列中定义的dp[i]无法记录最长递增子序列的个数,所以,我们这里需要再定义一个数组cnts[n]用以记录最长递增子序列的个数。
- dp数组的动态转移是比较容易的,那cnts数组的状态转移如何进行呢?实际上,我们可以仿照dp状态转移的思路来转移cnts数组的状态。具体来说,在找到新的上升子序列时,cnts数组需要重置为cnts[j],而如果找到相同长度的递增子序列时,则需要累加cnts[j]表示最长递增子序列的个数增加了。
class Solution {
public int findNumberOfLIS(int[] nums) {
int n = nums.length;
// dp[i]表示以i结尾的最长递增子序列长度
int[] dp = new int[n];
// cnts[i]表示以i结尾的最长递增子序列的个数
int[] cnts = new int[n];
// 记录最长值
int maxs = 0;
// 记录最长递增子序列的个数
int ans = 0;
for(int i=0; i<n; i++){
dp[i] = 1;
cnts[i] = 1;
for(int j=0; j<i; j++){
if(nums[i] > nums[j]){
if(dp[j] + 1 > dp[i]){
// 此时原来的递增子序列并不是最长的,需要更新
dp[i] = dp[j] + 1;
cnts[i] = cnts[j];// 重置cnts[i]
}else if(dp[j] + 1 == dp[i]){
// 出现一个相同长度的最长递增子序列
cnts[i] += cnts[j];
}
}
}
if(dp[i] > maxs){
maxs = dp[i];
ans = cnts[i];
}else if(dp[i] == maxs){
// 出现相同长度的自增子序列
ans += cnts[i];
}
}
return ans;
}
}
Either Excellent or Rusty