673. 最长递增子序列的个数
673. 最长递增子序列的个数
🟠 🔖 树状数组
线段树
数组
动态规划
🔗 力扣
LeetCode
题目
Given an integer array nums
, return the number of longest increasing subsequences.
Notice that the sequence has to be strictly increasing.
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 the longest increasing subsequence is 1, and there are 5 increasing subsequences of length 1, so output 5.
Constraints:
1 <= nums.length <= 2000
-10^6 <= nums[i] <= 10^6
- The answer is guaranteed to fit inside a 32-bit integer.
题目大意
给定一个未排序的整数数组 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
-10^6 <= nums[i] <= 10^6
解题思路
定义
dp
数组dp[i][0]
:表示以nums[i]
结尾的 最长递增子序列长度。dp[i][1]
:表示以nums[i]
结尾的 最长递增子序列的个数。- 初始化
dp[i] = [1, 1]
,因为单个元素本身就是一个长度为1
的递增子序列,个数为1
。
双层循环构建
dp
- 遍历
nums[i]
之前的所有nums[j]
,如果nums[i] > nums[j]
,说明nums[i]
可以接在nums[j]
后面形成更长的递增子序列。 - 更新
dp[i]
的最长长度:- 如果
dp[j][0] + 1 > dp[i][0]
,说明找到了更长的递增子序列,更新dp[i] = [dp[j][0] + 1, dp[j][1]]
。 - 如果
dp[j][0] + 1 == dp[i][0]
,说明找到了相同长度的递增子序列,需要累加dp[i][1]
。
- 如果
- 遍历
更新全局最长递增子序列长度
- 维护
maxLen
记录dp[i][0]
中的最大值。
- 维护
计算最终结果
- 遍历
dp
数组,统计dp[i][1]
,其中dp[i][0] == maxLen
,即所有 最长递增子序列的个数 之和。
- 遍历
复杂度分析
- 时间复杂度:
O(n^2)
,双层遍历nums
,每个元素与前面所有元素进行比较。 - 空间复杂度:
O(n)
,需要dp
数组存储每个位置的最长递增子序列信息。
代码
/**
* @param {number[]} nums
* @return {number}
*/
var findNumberOfLIS = function (nums) {
const n = nums.length;
if (n === 0) return 0;
// dp[i][0] = 以 nums[i] 结尾的最长递增子序列长度
// dp[i][1] = 以 nums[i] 结尾的最长递增子序列个数
const dp = Array.from({ length: n }, () => [1, 1]);
let maxLen = 1;
for (let i = 0; i < n; i++) {
for (let j = 0; j < i; j++) {
if (nums[i] > nums[j]) {
if (dp[i][0] < dp[j][0] + 1) {
dp[i] = [dp[j][0] + 1, dp[j][1]];
} else if (dp[i][0] === dp[j][0] + 1) {
dp[i][1] += dp[j][1];
}
}
}
maxLen = Math.max(maxLen, dp[i][0]);
}
// 统计所有最长子序列的个数
return dp.reduce(
(total, [length, count]) => total + (length === maxLen ? count : 0),
0
);
};
相关题目
题号 | 标题 | 题解 | 标签 | 难度 | 力扣 |
---|---|---|---|---|---|
300 | 最长递增子序列 | [✓] | 数组 二分查找 动态规划 | 🟠 | 🀄️ 🔗 |
674 | 最长连续递增序列 | [✓] | 数组 | 🟢 | 🀄️ 🔗 |
2407 | 最长递增子序列 II | 树状数组 线段树 队列 4+ | 🔴 | 🀄️ 🔗 |