E03 线性DP 最长上升子序列 - 董晓 - 博客园 (cnblogs.com)
给定一长度位为n的序列,求数值严格单调递增的子序列的长度最长是多少
f[i]:所有以第i个数结尾的上升子序列的长度
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 1010;
int n;
int a[N], f[N];//状态转移方程
int main(){
cin>>n;
for(int i = 1; i<=n; i++) cin>>a[i];
for(int i = 1; i<=n; i++){
f[i] = 1;//初始化
for(int j = 1; j<i; j++)
if(a[j]<a[i])//满足递增时再更新
f[i] = max(f[i], f[j]+1);
}
int res = 0;
for(int i = 1; i<=n; i++)
res = max(res, f[i]);
cout<<res;
return 0;
}
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=1010;
int n, a[N];
int f[N];//动态转移:第i个数的上升子序列
//递推式:1)由小到大(最优子结构)
// 2)由过去推现在(无后效性)
int main(){
cin>>n;
for(int i=1; i<=n; i++) cin>>a[i];
for(int i=1; i<=n; i++) f[i]=1;
for(int i=1; i<=n; i++)//遍历
for(int j=1; j<i; j++)//动态更新
if(a[j]<a[i]) f[i]=max(f[i],f[j]+1);
int res=0;
for(int i=1; i<=n; i++) res=max(res,f[i]);
cout<<res;
}
线性DP,二分优化:
把内层循环改为二分查找(logn)-->(nlogn),新定义一个b数组存储上升子序列;关键要动态更新b数组
因为要求的是长度,所以b数组中具体是啥无所谓(不一定是上升子序列),只需更新lenth
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=100010;
int n, a[N];
int len, b[N]; //记录上升子序列
int main(){
scanf("%d", &n);
for(int i=0; i<n; i++) scanf("%d", &a[i]);
b[0]=-2e9; //哨兵
for(int i=0; i<n; i++)
if(b[len]<a[i]) b[++len]=a[i]; //新数大于队尾数,则插入队尾
else *lower_bound(b,b+len,a[i])=a[i]; //替换第一个大于大于a[i]的数(贪心)
printf("%d\n", len);
}