673. 最长递增子序列的个数
给定一个未排序
的整数数组,找到最长递增子序列的个数
。
示例 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。
注意: 给定的数组长度不超过 2000 并且结果一定是32位有符号整数。
「最长递增子序列」那道题谁让求最长子序列的长度,这道题是求个数。
思路:
首先要定义 dp 数组的含义:
len[i]
表示以 nums[i]
这个数结尾
的最长递增子序列的长度
cnt[i]
表示以 nums[i]
这个数结尾
的,且最长递增子序列为len[i]
的组合数
index |
0 |
1 |
2 |
3 |
4 |
5 |
nums |
1 |
3 |
5 |
4 |
7 |
6 |
len |
1 |
2 |
3 |
3 |
4 |
4 |
cnt |
1 |
1 |
1 |
1 |
2 |
2 |
以nums[i]
为结尾,那么肯定要找前面比nums[i]
小的。
cnt[i]
= 所有的前面比nums[i]
小的,且等于len[i]-1
的len[j]
的个数
比如上面的例子:
求cnt[3]
简而言之就是:cnt[i]
等于 len[j]
的个数,只不过这个len[j]
要满足三个条件:
i < j
nums[j] < nums[i]
len[j] == len[i] -1
最后返回的结果:
- 先求得
len[]
的最大值MAX
- 返回所有
len[]
中等于MAX的索引所对应的cnt
的和
最终代码如下:
class Solution {
public int findNumberOfLIS(int[] nums) {
int LEN = nums.length;
int[] len = new int[LEN];
int[] cnt = new int[LEN];
Arrays.fill(len, 1);
Arrays.fill(cnt, 1);
for(int i = 1; i < LEN; i++){
for(int j = 0; j < i; j++){
if(nums[j] < nums[i]){
if(len[j] > len[i] - 1){
len[i] = len[j] + 1;
cnt[i] = cnt[j];
}else if(len[j] == len[i] - 1){
cnt[i] += cnt[j];
}
}
}
}
// 只需遍历一遍就可找出dp数组中最大值的个数
int MAX = 0; // 保存当前最大值
int res = 0; // 保存当前最大值的个数
for(int i = 0; i < LEN; i++){
MAX = Math.max(MAX, len[i]);
}
for(int i = 0; i < LEN; i++){
if(len[i] == MAX){
res += cnt[i];
}
}
return res;
}
}
时间复杂度:O(N^2)
空间复杂度:O(N)