题目 最长递增子序列
给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。
子序列是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7]
是数组 [0,3,1,6,2,2,7]
的子序列。
题解| 动态规划
假如考虑dp[i]
这个元素,以第 ii 个数字结尾的最长上升子序列的长度,注意nums[i]
必须被选取。
状态转移方程:dp[i] = max(dp[j] + 1, dp[i]); (j < i)
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
int n = nums.size();
vector<int> dp(n, 1);
dp[0] = 1;
for(int i = 1; i < n; i++){
for(int j = 0; j < i; ++j){
if(nums[j] < nums[i]){
dp[i] = max(dp[j] + 1, dp[i]);
}
}
}
return *max_element(dp.begin(), dp.end());
}
};
题目 最长递增子序列的个数
给定一个未排序的整数数组,找到最长递增子序列的个数。
题解 动态规划
在题目|的基础上,让统计子序列的数目,我们可以增一个cnt
容器专门记录到达某个位置的子序列数目。
在题目|的前提下:
注意:如果dp[j] + 1 > dp[i]
,说明最长递增子序列的长度增加了,dp[i] = dp[j] + 1
,长度增加,数量不变 count[i] = count[j]
如果dp[j] + 1 == dp[i]
,说明最长递增子序列的长度并没有增加,但是出现了长度一样的情况,数量增加 count[i] += count[j]
class Solution {
public:
int findNumberOfLIS(vector<int>& nums) {
int len = nums.size();
vector<int> dp(len, 1);
vector<int> cnt(len, 1);
for(int i = 1; i < len; ++i){
for(int j = 0; j < i; ++j){
if(nums[j] < nums[i]){
if(dp[j] + 1 > dp[i]){
dp[i] = dp[j] + 1;
cnt[i] = cnt[j];
}
else if(dp[j] + 1 == dp[i]){
cnt[i] += cnt[j];
}
}
}
}
int num = *max_element(dp.begin(), dp.end());
int ans = 0;
for(int i = 0; i < len; ++i){
if(dp[i] == num){
ans += cnt[i];
}
}
return ans;
}
};
最长数对链
给出 n
个数对。 在每一个数对中,第一个数字总是比第二个数字小。
现在,我们定义一种跟随关系,当且仅当 b < c
时,数对(c, d)
才可以跟在 (a, b)
后面。我们用这种形式来构造一个数对链。
给定一个数对集合,找出能够形成的最长数对链的长度。你不需要用到所有的数对,你可以以任何顺序选择其中的一些数对来构造。
题解 动态规划
与第一题一摸一样的思路,只是把数字换成了数字对,极其类似。
class Solution {
public:
int findLongestChain(vector<vector<int>>& pairs) {
int len = pairs.size();
vector<int> dp(len , 1);
sort(pairs.begin(), pairs.end());
for(int i = 1; i < len; ++i){
for(int j = 0; j < i; ++j){
if(pairs[j][1] < pairs[i][0]){
dp[i] = max(dp[i], dp[j] + 1);
}
}
}
return *max_element(dp.begin(), dp.end());
}
};