1.最长上升子序列
1.不连续的情况
最长上升子序列作为线性dp的模板题
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
int s[1005];
int dp[1005];
/*最长上升子序列
* 本题的dp思路是:第i个元素构成一个单调子序列时它前面的元素可能是来自前面任意一个元素
* 或者前面没有一个元素是比他小的,他自己本身作为一个序列,长度是1
* 那么我们要考虑两个情况:1.它本身是(1~i)中最小的元素时候 他的值是1
* 2.它本身比前面的一个元素小时,他的值就是这个元素目前的序列长度+1
* 我们要遍历N个元素
我们要遍历第i个元素的前i-1个元素 ---》二重循环
*
*/
int pre[1000];
int main()
{
int N;
cin >> N;
for (int i = 1;i <= N;i++)
cin >> s[i];
dp[1] = 1;
for(int i=1;i<=N;i++)
for (int j = 1;j <= i;j++)
{
if (i == j && dp[i] == 0)
dp[i] = 1; //如果前面为空,就设置他的子序列为一
if (s[j] < s[i])
{
dp[i] = max(dp[j] + 1, dp[i]); //保证递增性
pre[i] = j; //保存轨迹
}
}
int ans = -1;
for (int i = 1;i <= N;i++)
ans = max(ans, dp[i]);
cout << ans;
}
2.连续的情况
连续的情况比较好分析,就是在一个给定的序列中,比较前后是不是符合(前一个<后一个)即可,如果不符合的话,就直接断开,符合的话让下标存储值+1
#include <iostream>
#include <algorithm>
using namespace std;
/*本题分析的是连续的情况,时间复杂度O(n)*/
int a[1005];
int dp[1005];
int main()
{
int n;
cin >> n;
for (int i = 1;i <= n;i++)
cin >> a[i];
dp[1] = 1;
int ans = -1;
for (int i = 2;i <= n;i++)
{
if (a[i - 1] < a[i])
{
dp[i] = dp[i - 1] + 1;
}
else
dp[i] = 1;
ans = max(ans, dp[i]);
}
cout << ans;
}
3.二维最长递增子序列(信封嵌套问题)
一定数量的信封,带有整数对 (w, h) 分别代表信封宽度和高度。一个信封的宽高均大于另一个信封时可以放下另一个信封。
求最大的信封嵌套层数。样例
样例 1:输入:[[5,4],[6,4],[6,7],[2,3]]
输出:3
解释:
最大的信封嵌套层数是 3 ([2,3] => [5,4] => [6,7])。
二维的递增子序列问题可以先按照某种顺序排序,排序完之后再根据贪心的策略找到最大的嵌套层数。所以二维的递增子序列问题本质上是一种贪心问题