给定一个长度为 N 的数列,求数值严格单调递增的子序列的长度最长是多少。
例如:3 1 2 1 8 5 6这个序列的最长递增子序列长度为4(1 2 5 6)。
输入格式:
第一行包含整数 N ;第二行包含 N 个整数,表示完整序列。
输出格式:
输出一个整数,表示最大长度。
数据范围:
1 <= N <= 1000 ,-1e9 < 序列元素 <1e9 。
假设序列起始位置为 1 ,集合 k 表示以 k 位置为结尾的上升子序列的集合,f[k] 为 k 集合中的上升子序列中的最长的上升子序列的长度;
由于以 k 位置结尾的上升子序列一定是由以 1 ~ k-1 位置结尾的上升子序列连接得到,故 k 集合可以划分为1、2……,k -1(1表示以 1 位置为结尾的上升子序列的集合,2 表示以 2 位置为结尾的上升子序列的集合…… k-1 表示以 k-1 位置为结尾的上升子序列的集合 );
由上述可知,f[i] = max( f[1] ~ f[i-1]) +1;
故可以从前往后枚举,每次枚举中查找 1 ~ i-1,若查找到的 f[j] < f[i],则 f[i] = max( f[i] , f[j] + 1 );
初始状态 f[i] = 1;
时间复杂度为O(n^2)。
#include
using namespace std;
const int N = 1010;
int f[N], a[N];
int n, res = 1;
int main() {
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> a[i];
f[i] = 1;
for (int j = 1; j < i; j++)
if (a[j] < a[i]) {
f[i] = max(f[i], f[j] + 1);
res = max(res, f[i]);
}
}
cout << res;
return 0;
}
时间复杂度可优化至O( nlogn ),步骤如下:
从前到后遍历序列;
1. 给定一个单调递增栈;
2. 如果当前遍历到的元素大于栈顶元素,则将当前元素加入栈顶;
3. 如果当前元素小于等于栈顶,则在栈中查找第一个大于等于当前元素的元素,用当前元素替换掉找到的元素,二分查找时间复杂度O( logn );
栈的大小就是最长上升子序列的长度。
二分算法:二分算法_二分排序算法_如何何何的博客-CSDN博客
#include
using namespace std;
const int N=1e5;
int q[N],g[N];
int n=1,res;
void check(int x){
//找到第一个大于等于q[x]的
int l=0,r=res,mid;
while(l>1;
if(g[mid]>=q[x])r=mid;
else l=mid+1;
}
g[l]=q[x];
}
int main(){
cin>>n;
for(int i=1;i<=n;i++)cin>>q[i];
//while(cin>>a[n++]);
//n--;
g[0]=q[1];
for(int i=2;i<=n;i++){
if(q[i]>g[res])g[++res]=q[i];
else check(i);
}
//for(int i=0;i
怪盗基德的滑翔翼 - C语言网 (dotcpp.com)
一个方向的最长下降子序列等于反方向的最长上升子序列;
求出从前往后和从后往前的最长上升子序列即可。
#include
using namespace std;
const int N=110;
int f_l[N],f_r[N];//往左和往右的最长上升子序列
int a[N];
int main(){
int T;
cin>>T;
while(T--){
int n;
cin>>n;
for(int i=0;i>a[i];
int res=0;
//正向最长上升子序列
for(int i=0;i-1;i--){
f_l[i]=1;
for(int j=n-1;j>i;j--)
if(a[j]
登山 - C语言网 (dotcpp.com)
假设 f[i] 为以 i 号山为最高山时,能游览的山的最大数量;
f[i] 为以 i 点的山为终点左侧序列的最长上升子序列的长度,加上以 i 点的山为起点右侧最长下降子序列的长度,再减去 1 ;
求最长下降子序列即反向求最长上升子序列。
#include
using namespace std;
const int N=1010;
int f_l[N],f_r[N];//往左和往右的最长上升子序列
int a[N];
int main(){
int n;
cin>>n;
for(int i=0;i>a[i];
//正向最长上升子序列
for(int i=0;i-1;i--){
f_l[i]=1;
for(int j=n-1;j>i;j--)
if(a[j]