Medium
题目描述
给定一个整数数组 nums,返回最长递增子序列的个数。
注意子序列必须是严格递增的。
示例 1:
输入: nums = [1,3,5,4,7]
输出: 2
解释: 有两个最长递增子序列,分别是 [1, 3, 4, 7] 和 [1, 3, 5, 7]。
示例 2:
输入: nums = [2,2,2,2,2]
输出: 5
解释: 最长递增子序列的长度是 1,长度为 1 的递增子序列有 5 个,因此输出 5。
提示:
1 <= nums.length <= 2000-10^6 <= nums[i] <= 10^6- 答案保证在 32 位整数范围内。
解题思路
这道题是经典的最长递增子序列(LIS)问题的变形,不仅要求最长长度,还要统计满足条件的子序列个数。
解题思路: 使用动态规划来解决。我们需要维护两个数组:
dp[i]:表示以nums[i]结尾的最长递增子序列的长度count[i]:表示以nums[i]结尾的最长递增子序列的个数
状态转移:
- 对于每个位置
i,我们遍历前面所有位置j(j < i) - 如果
nums[j] < nums[i],说明可以将nums[i]接在以nums[j]结尾的递增子序列后面 - 如果
dp[j] + 1 > dp[i],说明找到了更长的递增子序列,更新dp[i]和count[i] - 如果
dp[j] + 1 == dp[i],说明找到了另一种达到相同最长长度的方案,累加count[i]
算法步骤:
- 初始化所有
dp[i] = 1,count[i] = 1(每个元素本身构成长度为1的子序列) - 双重循环进行状态转移
- 找出全局最长长度
maxLen - 累加所有
dp[i] == maxLen对应的count[i]
代码实现
class Solution {
public:
int findNumberOfLIS(vector<int>& nums) {
int n = nums.size();
if (n == 0) return 0;
vector<int> dp(n, 1); // dp[i]: 以nums[i]结尾的最长递增子序列长度
vector<int> count(n, 1); // count[i]: 以nums[i]结尾的最长递增子序列个数
for (int i = 1; i < n; i++) {
for (int j = 0; j < i; j++) {
if (nums[j] < nums[i]) {
if (dp[j] + 1 > dp[i]) {
dp[i] = dp[j] + 1;
count[i] = count[j];
} else if (dp[j] + 1 == dp[i]) {
count[i] += count[j];
}
}
}
}
int maxLen = *max_element(dp.begin(), dp.end());
int result = 0;
for (int i = 0; i < n; i++) {
if (dp[i] == maxLen) {
result += count[i];
}
}
return result;
}
};
class Solution:
def findNumberOfLIS(self, nums: List[int]) -> int:
n = len(nums)
if n == 0:
return 0
dp = [1] * n # dp[i]: 以nums[i]结尾的最长递增子序列长度
count = [1] * n # count[i]: 以nums[i]结尾的最长递增子序列个数
for i in range(1, n):
for j in range(i):
if nums[j] < nums[i]:
if dp[j] + 1 > dp[i]:
dp[i] = dp[j] + 1
count[i] = count[j]
elif dp[j] + 1 == dp[i]:
count[i] += count[j]
max_len = max(dp)
result = 0
for i in range(n):
if dp[i] == max_len:
result += count[i]
return result
public class Solution {
public int FindNumberOfLIS(int[] nums) {
int n = nums.Length;
if (n == 0) return 0;
int[] dp = new int[n]; // dp[i]: 以nums[i]结尾的最长递增子序列长度
int[] count = new int[n]; // count[i]: 以nums[i]结尾的最长递增子序列个数
// 初始化
for (int i = 0; i < n; i++) {
dp[i] = 1;
count[i] = 1;
}
for (int i = 1; i < n; i++) {
for (int j = 0; j < i; j++) {
if (nums[j] < nums[i]) {
if (dp[j] + 1 > dp[i]) {
dp[i] = dp[j] + 1;
count[i] = count[j];
} else if (dp[j] + 1 == dp[i]) {
count[i] += count[j];
}
}
}
}
int maxLen = dp.Max();
int result = 0;
for (int i = 0; i < n; i++) {
if (dp[i] == maxLen) {
result += count[i];
}
}
return result;
}
}
/**
* @param {number[]} nums
* @return {number}
*/
var findNumberOfLIS = function(nums) {
const n = nums.length;
if (n === 0) return 0;
const lengths = new Array(n).fill(1);
const counts = new Array(n).fill(1);
for (let i = 1; i < n; i++) {
for (let j = 0; j < i; j++) {
if (nums[i] > nums[j]) {
if (lengths[j] + 1 > lengths[i]) {
lengths[i] = lengths[j] + 1;
counts[i] = counts[j];
} else if (lengths[j] + 1 === lengths[i]) {
counts[i] += counts[j];
}
}
}
}
const maxLength = Math.max(...lengths);
let result = 0;
for (let i = 0; i < n; i++) {
if (lengths[i] === maxLength) {
result += counts[i];
}
}
return result;
};
复杂度分析
| 复杂度类型 | 值 | 说明 |
|---|---|---|
| 时间复杂度 | O(n²) | 双重循环遍历数组进行状态转移 |
| 空间复杂度 | O(n) | 使用两个长度为 n 的数组存储 dp 和 count 信息 |