Your program, when given the numeric sequence, must find the length of its longest ordered subsequence.
InputThe first line of input file contains the length of sequence N. The second line contains the elements of sequence - N integers in the range from 0 to 10000 each, separated by spaces. 1 <= N <= 1000
Output file must contain a single integer - the length of the longest ordered subsequence of the given sequence.
7
1 7 3 5 9 4 8
4
题意:求最长上升子序列的元素个数有多少个
思路:DP,
递推公式:dp[i] = max(dp[i],dp[j]+1) (j<i且a[j]<a[i],1为本身的个数)
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <math.h>
#include <stdlib.h>
using namespace std;
const int MAXN=1010;
int n;
int a[MAXN];
int dp[MAXN];
void solve(){
int result=0;
for(int i=0;i<n;i++){
dp[i]=1;
for(int j=0;j<i;j++){
if(a[i]>a[j])
dp[i]=max(dp[i],dp[j]+1);
}
result=max(result,dp[i]);
}
printf("%d\n",result);
return ;
}
int main()
{
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
solve();
return 0;
}
本份代码接近O(n*n),耗时间太多,下面用二分优化
新建一个dp数组,dp[i]表示长度为i的LIS结尾元素的最小值。对于一个上升子序列,显然其结尾元素越小,越有利于在后面接其他的元素,也就越可能变得更长。因此,我们只需要维护dp数组,对于每一个a[i],如果a[i] > dp[当前最长的LIS长度],就把a[i]接到当前最长的LIS后面,即dp[++当前最长的LIS长度]=a[i]。
那么,怎么维护low数组呢?对于每一个a[i],如果a[i]能接到LIS后面,就接上去;否则,就用a[i]取更新low数组。具体方法是,在dp数组中找到第一个大于等于a[i]的元素dp[j],用a[i]去更新dp[j]。如果从头到尾扫一遍dp数组的话,时间复杂度仍是O(n^2)。我们注意到dp数组内部一定是单调不降的,所有我们可以二分dp数组,找出第一个大于等于a[i]的元素。二分一次low数组的时间复杂度的O(lgn),所以总的时间复杂度是O(nlogn)。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <cmath>
#include <cstdio>
typedef long long ll;
#define N 1005
using namespace std;
int len,a[N],dp[N];
/*
二分查找。 注意,这个二分查找是求下界的; (什么是下界?详情见《算法入门经典》 P145)
即返回 >= 所查找对象的第一个位置(想想为什么)
也可以用STL的lowe_bound二分查找求的下界
*/
int binary_search(int i)
{
int l,r,mid;
l=0,r=len;
while(l<r)
{
mid = l+(r-l)/2;
if(dp[mid]>=a[i]) r=mid;
else l=mid+1;
}
return l;
}
int main()
{
int n;
while(scanf("%d",&n)==1){
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
dp[1]=a[1];
len=1;
for(int i=2;i<=n;i++)
{
if(a[i]>dp[len])
dp[++len]=a[i];
else
{
int pos=binary_search(i);
dp[pos]=a[i];
}
}
printf("%d\n",len);
}
return 0;
}
或者
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <cmath>
#include <cstdio>
typedef long long ll;
#define N 1005
using namespace std;
int len,a[N],dp[N];
int main()
{
int n;
while(scanf("%d",&n)==1){
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
dp[1]=a[1];
len=1;
for(int i=2;i<=n;i++)
{
if(a[i]>dp[len])
dp[++len]=a[i];
else
{
int pos=lower_bound(dp,dp+len,a[i])-dp;
dp[pos]=a[i];
}
}
printf("%d\n",len);
}
return 0;
}