合唱队形题
题目分析 :分别求最长上升和下降子序列。
题目分析 :这道题差不多是个水题了,不过我在做题的被误导了,虽然结果正确却超时了。我们用上升子序列的时间复杂度是:O(n*n);
题目收获 :需要对时间复杂和空间复杂度进行深刻的重新理解。
AC代码 :
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#define maxn 105
using namespace std;
int d[maxn],b[maxn],num;
int pepo[maxn];
int main()
{
//freopen("in.txt", "r", stdin);
scanf("%d", &num);
memset(d, 0, sizeof(d));
memset(b, 0, sizeof(b));
for (int i = 1; i <= num; i++)
scanf("%d", &pepo[i]);
for (int i = 2; i <= num; i++)
for (int j = 1; j < i; j++)
if (pepo[i] > pepo[j])
d[i] = max(d[i], d[j] + 1);
for (int i = num - 1; i >= 1; i--)
for (int j = num; j > i; j--)
if (pepo[i] > pepo[j])
b[i] = max(b[i], b[j] + 1);
int ans = 0;
for (int i = 1; i <= num; i++)
ans = max(ans, b[i] + d[i]);
printf("%d
", num - ans - 1);
return 0;
}
然,我在参考他人的代码时发现,还存在一种时间复杂度为O(n*logn)的算法,这就给我们一个面对大量数据时,不用担心超时的问题。假设一组数p[]={2 1 5 3 6 4 8 9 7} ,现在求它的上升子序列。
我们用b[0]存p[0],即b[0]=2;
然后发现1<2,所以b[0]=p[1]=1;被替换掉了。
我们知道5>1,b[0+1]=b[1]=p[2]=5;此时b[]={1,5};
到了p[3]=3<5;我们继续替换b[2]=p[3]=3;此时b[]={1,3};
又到6>3,b[2+1]=b[3]=p[4]=6;此时b[]={1,3,6};
一次推下去知道,b[]={1,3,4,8,9}
最后发现:7<9;所以我们8替换为7.(这样做的目的是为了在后面加数字的时候任可以保持正确性)
代码实现:二分法。
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 105;
int fup[maxn],fdown[maxn],p[maxn];
int search(int x, int y,int num)
{
int mid = 0;
while (x < y)
{
if (num > fup[mid = (x + y) >> 1])//二分求num值应该在的位置
x = mid + 1;
else
y = mid;
}
return x;
}
int main()
{
freopen("in.txt", "r", stdin);
int t, k = 0;
while (cin >>t && t)
{
memset(fup, 0, sizeof(fup));
memset(fdown, 0, sizeof(fdown));
memset(p, 0, sizeof(p));
for (int i = 0; i < t; i++)
scanf("%d", &p[i]);
int j = 1;//初始化位置;
for (int i = 0; i < t; i++)//从0开始遍历
{
if (fup[k = search(0, j - 1, p[i])] >= p[i])
fup[k] = p[i];
else
fup[j++] = p[i];
}
}
return 0;
}