最长递增子序列

【dp】最长递增子序列和最长递增子序列的个数_递增子序列

class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
int n = nums.size();
vector<int> dp(n, 1); // dp[i]:算上nums[i],最长递增子序列的长度
int ans = 1;
for(int i = 1; i < n; i++){
for(int j = 0; j < i; j++){
// 遍历nums[0 ~ i-1],找比nums[i]小的元素nums[j]
// 求出使用nums[i]能构成的最长递增子序列的长度dp[i]
if(nums[j] < nums[i]) dp[i] = max(dp[i], dp[j] + 1);
}
ans = max(ans, dp[i]);
}
return ans;
}
};

最长递增子序列的个数

【dp】最长递增子序列和最长递增子序列的个数_算法_02

【dp】最长递增子序列和最长递增子序列的个数_算法_03

可以先求出dp数组,根据dp数组计算cnt数组,这种思路比较直接,好理解

当前dp[i]计算出来后,就可以查看0 ~ i-1元素中哪些元素比nums[i]小,且最长子序列长度dp[j]比当前最长子序列长度dp[i]小1,说明当前最长子序列长度用到了j号元素,cnt[i] += cnt[j]

class Solution {
public:
int findNumberOfLIS(vector<int>& nums) {
int n = nums.size();
vector<int> dp(n, 1); // dp[i]:算上nums[i],最长递增子序列的长度
vector<int> cnt(n, 0);
cnt[0] = 1;
int max_len = 1;
for (int i = 1; i < n; i++) {
for (int j = 0; j < i; j++) {
if (nums[j] < nums[i]) {
dp[i] = max(dp[i], dp[j] + 1);
}
}
max_len = max(max_len, dp[i]);
for (int j = 0; j < i; j++) {
// 算上nums[i],当前最长递增子序列的个数
if (dp[j] == dp[i] - 1 && nums[j] < nums[i]) cnt[i] += cnt[j];
}
// 无法和前面的数构成递增序列,自己就是一个递增序列
if (cnt[i] == 0) cnt[i] = 1;
}
int ans = 0;
for (int i = 0; i < n; i++) {
if (dp[i] == max_len) ans += cnt[i];
}
return ans;
}
};

dp数组和cnt数组也可以同步动态更新

需要遍历dp[0 ~ i-1],才能求出dp[i],如果前面某个dp[j] + 1大于当前dp[i],则说明构成当前最长子序列dp[i],可能用到nums[j],更新dp[i]的同时更新cnt[i],直接用cnt[j]赋值

如果遍历dp[0 ~ i-1]的过程中,又遇到了一个dp[j],可以构成和当前一样长的子序列,则说明通过当前dp[j]也可构成和目前子序列一样长的递增子序列,则cnt[i] += cnt[j]

class Solution {
public:
int findNumberOfLIS(vector<int>& nums) {
int n = nums.size();
vector<int> dp(n, 1); // dp[i]:算上nums[i],递增子序列的长度
vector<int> cnt(n, 1); // cnt[i]:使用nums[i],递增子序列的个数
int max_len = 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]){
// 从下标j的位置和下标i的位置,可以构成递增子序列
// 在0 ~ i-1范围内,找到了更长的递增子序列,cnt[i]用cnt[j]更新
dp[i] = dp[j] + 1;
cnt[i] = cnt[j]; // 记录构成更长递增子序列的序列数量
}else if (dp[j] + 1 == dp[i]){
// 使用当前的j号元素和当前i号元素,也可构成递增子序列,加上cnt[j]
cnt[i] += cnt[j];
}
}
}
max_len = max(max_len, dp[i]);
}
int ans = 0;
for (int i = 0; i < n; i++) {
if (dp[i] == max_len) ans += cnt[i];
}
return ans;
}
};