前言
要开始认真写题解了,不然做一道忘一道
题目描述
给定一个未排序的整数数组,找到最长递增子序列的个数。
- 示例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。
解题思路
LIS变形题,显然是用动态规划的方法做,求长度自然是没问题的,可是求个数貌似会遇到点问题,这里我们如果像求常规LIS一样只用一个数组记录以
n
u
m
s
[
i
]
nums[i]
nums[i]结尾的最长上升子序列长度会发现很不好列状态转移方程,因此我们考虑可以用LIS的思路辅助求解,我们用
l
e
n
g
t
h
length
length数组来表示以
n
u
m
s
[
i
]
nums[i]
nums[i]结尾的LIS的长度,以
c
n
t
cnt
cnt数组来表示以
n
u
m
s
[
i
]
nums[i]
nums[i]结尾的LIS的个数,我们可以发现有如下转移方程
对于固定的
i
i
i和
∀
\forall
∀
j
<
i
j<i
j<i,如果
n
u
m
s
[
i
]
>
n
u
m
s
[
j
]
nums[i]>nums[j]
nums[i]>nums[j]
- 如果 l e n g t h [ i ] < l e n g t h [ j ] + 1 length[i] < length[j]+1 length[i]<length[j]+1,这个时候说明找到了一条更长的LIS序列,我们把 l e n g t h [ i ] length[i] length[i]更新为 l e n g t h [ j ] + 1 length[j]+1 length[j]+1,并且把 c n t [ i ] cnt[i] cnt[i]更新为 c n t [ j ] cnt[j] cnt[j]
- 如果 l e n g t h [ i ] = = l e n g t h [ j ] + 1 length[i] == length[j]+1 length[i]==length[j]+1,这个时候说明找到了一条新的LIS序列,我们把 c n t [ i ] cnt[i] cnt[i]加上 c n t [ j ] cnt[j] cnt[j]即可
如果不好理解的话,我们可以用一个图来模拟一下,比如输入为[1,3,5,4,7]
下面画出
i
i
i从0到4的dp表格
n u m s [ i ] nums[i] nums[i] | 1 | 3 | 5 | 4 | 7 |
---|---|---|---|---|---|
l e n g t h [ i ] length[i] length[i] | 1 | 1 | 1 | 1 | 1 |
c n t [ i ] cnt[i] cnt[i] | 1 | 1 | 1 | 1 | 1 |
n u m s [ i ] nums[i] nums[i] | 1 | 3 | 5 | 4 | 7 |
---|---|---|---|---|---|
l e n g t h [ i ] length[i] length[i] | 1 | 2 | 1 | 1 | 1 |
c n t [ i ] cnt[i] cnt[i] | 1 | 1 | 1 | 1 | 1 |
n u m s [ i ] nums[i] nums[i] | 1 | 3 | 5 | 4 | 7 |
---|---|---|---|---|---|
l e n g t h [ i ] length[i] length[i] | 1 | 2 | 3 | 1 | 1 |
c n t [ i ] cnt[i] cnt[i] | 1 | 1 | 1 | 1 | 1 |
n u m s [ i ] nums[i] nums[i] | 1 | 3 | 5 | 4 | 7 |
---|---|---|---|---|---|
l e n g t h [ i ] length[i] length[i] | 1 | 2 | 3 | 3 | 1 |
c n t [ i ] cnt[i] cnt[i] | 1 | 1 | 1 | 1 | 1 |
n u m s [ i ] nums[i] nums[i] | 1 | 3 | 5 | 4 | 7 |
---|---|---|---|---|---|
l e n g t h [ i ] length[i] length[i] | 1 | 2 | 3 | 3 | 4 |
c n t [ i ] cnt[i] cnt[i] | 1 | 1 | 1 | 1 | 2 |
这样我们最后在 l e n g t h length length数组中找值为其中最大元素值的 l e n g t h [ i ] length[i] length[i],然后每次加上这个 i i i对应的 c n t [ i ] cnt[i] cnt[i]就可以得到正确答案
AC代码
class Solution {
public:
int findNumberOfLIS(vector<int>& nums) {
int len = nums.size();
vector<int>length(len, 1);
vector<int>cnt(len, 1);
int max_len = 1, res = 0;
for (int i = 0; i < len; i++) {
for (int j = 0; j < i; j++) {
if (nums[i] > nums[j]) {
if (length[i] == length[j] + 1) {
cnt[i] += cnt[j];
}
else if (length[i] < length[j] + 1) {
length[i] = length[j] + 1;
cnt[i] = cnt[j];
}
}
}
max_len = max(max_len, length[i]);
}
for (int i = 0; i < len; i++)
if (length[i] == max_len)
res += cnt[i];
return res;
}
};
小结
我还是对dp的力量一无所知…