Time Limit: 2000MS | Memory Limit: 65536K | |
Total Submissions: 54233 | Accepted: 24254 |
Description
Your program, when given the numeric sequence, must find the length of its longest ordered subsequence.
Input
Output
Sample Input
7 1 7 3 5 9 4 8
Sample Output
4
题意:求最长上升子序列的长度;
题解:两种算法:O( n ^ 2 ) 和 O( n * log n );
代码如下:
(1) O( n ^ 2 )
定义dp[ i ]: 以a[ i ]为结尾的最长上升子序列的长度。
那么以a[ i ]为结尾的上升子序列是以下其中之一
①只包含a[ i ]的子序列 (a[ i ]比前面的任何数都小,所以重新立一个序列)
②在满足 j < i 并且a[ j ] < a[ i ] 的以a[ j ] 为结尾的上升子序列末尾,再加上a[ i ]后得到的子序列
递推关系为: dp[ i ] = max { 1 , dp[ j ] + 1( 当 j < i 且a[ j ] < a[ i ] 时)}
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=1005;
int a[maxn];
int dp[maxn];
int main()
{
int n;
while(~scanf("%d",&n)){
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
int ans=0;
for(int i=0;i<n;i++){
dp[i]=1;
for(int j=0;j<i;j++){
if(a[j]<a[i])
dp[i]=max(dp[i],dp[j]+1);
}
ans=max(ans,dp[i]);
}
printf("%d\n",ans);
}
return 0;
}
(2) O( n * log n )
定义 dp[ i ]: 长度为 i + 1 的上升子序列中末尾元素的最小值
首先将 dp 数组初始化为 INF ,然后对 a数列中的元素逐个遍历;对于每个a[ i ] 的值,遍历所有 dp 直到找到一个dp[ j ]的值大于等于 a[ i ]然后用a[ i ]赋值给 dp[ j ];
最后记录 dp数组中 不为 INF的值的数量即可。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=1005;
const int INF=0x3f3f3f3f;
int a[maxn];
int dp[maxn];
int main()
{
int n;
while(~scanf("%d",&n)){
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
for(int i=0;i<n;i++)
dp[i]=INF;
int num=0;
for(int i=0;i<n;i++){
int pos=lower_bound(dp,dp+n,a[i])-dp;
dp[pos]=a[i];
}
for(int i=0;i<n;i++){
if(dp[i]!=INF) num++;
else break;
}
printf("%d\n",num);
}
return 0;
}