673. 最长递增子序列的个数 - 力扣(LeetCode)
目描述
给定一个未排序的整数数组 nums,返回最长递增子序列的个数。 注意:序列要求严格递增,子序列不要求连续。
示例 1: 输入:
nums = [1,3,5,4,7]最长递增子序列长度为 3,一共有 2 个:[1,3,5,7]、[1,3,4,7]输出:2示例 2: 输入:
nums = [2,2,2,2,2]最长递增子序列长度为 1,一共 5 个 输出:5
解题思路
本题是最长递增子序列 LIS 的变形题。普通 LIS 只需要求最长长度,本题额外要求统计有多少条这样的最长序列。
状态定义
len[i]:以nums[i]结尾的最长递增子序列的长度count[i]:以nums[i]结尾,长度等于len[i]的递增子序列的数量
初始条件: 每个元素自身单独就可以构成长度为 1 的子序列。 所以:len[i] = 1,count[i] = 1。
状态转移
遍历 i 作为子序列的结尾,再用 j 遍历 i 前面所有元素(j < i):
- 当
nums[i] > nums[j],说明nums[i]可以接在以nums[j]结尾的子序列后面- 若
len[j]+1 > len[i]:找到更长的子序列。更新长度len[i],方案数继承count[j] - 若
len[j]+1 == len[i]:发现同样长度 的新路径,方案数累加count[i] += count[j]
- 若
统计全局答案
维护两个全局变量:
maxLen:整个数组最长递增子序列的长度ans:最长递增子序列总个数 每次计算完len[i]后:
- 如果
len[i] > maxLen:发现了更长序列,更新maxLen,重置ans = count[i] - 如果
len[i] == maxLen:当前结尾的子序列也是最长,ans += count[i]
cpp
class Solution {
public:
int findNumberOfLIS(vector<int>& nums) {
int n = nums.size();
vector<int> len(n, 1);
vector<int> count(n, 1);
int maxLen = 1;
int ans = 1;
for (int i = 1; i < n; ++i) {
for (int j = 0; j < i; ++j) {
if (nums[i] > nums[j]) {
if (len[j] + 1 > len[i]) {
len[i] = len[j] + 1;
count[i] = count[j];
} else if (len[j] + 1 == len[i]) {
count[i] += count[j];
}
}
}
if (len[i] > maxLen) {
maxLen = len[i];
ans = count[i];
} else if (len[i] == maxLen) {
ans += count[i];
}
}
return ans;
}
};