题目描述
链接:https://ac.nowcoder.com/acm/problem/50940
来源:牛客网
For this problem, you will write a program that reads in a sequence of 32-bit signed integers. After each odd-indexed value is read, output the median (middle value) of the elements received so far.
来源:牛客网
For this problem, you will write a program that reads in a sequence of 32-bit signed integers. After each odd-indexed value is read, output the median (middle value) of the elements received so far.
翻译就不打了,相信各位大佬都能读懂,那我们直接上分析。
分析
思路一 对顶堆
就是我们可以建立两个堆,来维护比当前值大和小的数(就是以中位数为分界线,一个堆放比它小的数,一个堆放比它大的数),我们将数读进堆后,将它们进行比较,在放较小值的堆中,将较小值的最大值挤入堆顶,在放较大值的堆中,将较大值的最小值挤入堆顶,然后我们知道如果两个堆的大小之差超过1的话,那就说明还没分好,就将一个堆的堆顶弹到另一个堆中,如此反复,到最后差值为一时,说明分好了,弹出即可。
#include<bits/stdc++.h>
using namespace std;
int read()
{
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-48;ch=getchar();}
return x*f;
}
priority_queue<int> q;
priority_queue<int,vector<int>,greater<int> > p;
int n,t;
signed main()
{
t=read();
while(t--)
{
while(!q.empty()) q.pop();
while(!p.empty()) p.pop();
scanf("%d",&n);
printf("%d ",n);
n=read();
printf("%d\n",(n+1)/2);
for(int i=1;i<=n;i++)
{
int x=read();
if(p.empty()) p.push(x);
else if(x>=p.top()) p.push(x);
else q.push(x);
if(p.size()-q.size()>1)
{
q.push(p.top());
p.pop();
}
if(p.size()-q.size()<1)
{
p.push(q.top());
q.pop();
}
if(i%2)
printf("%d ",p.top());
if(!(i%20)) printf("\n");
}
puts("");
}
return 0;
} 思路二 链表
链表这个东西嘛,指针最大啦。我们开个结构体,分别记录数值,序号,前驱,后继。
然后我们来模拟一下就能发现规律
假设我们一直读到最后一个,中位数那就是(n+1)/2,然后我们将最末尾的删掉,然后如果一直这样,我们可以发现,如果删掉的数在上一个中位数的右边,新的中位数就向前移一个单位,如果删掉的数在上一个中位数的左边,新的中位数就向后移一个单位
此规律一出,那不就简单的有手就行#include<bits/stdc++.h>
using namespace std;
int read()
{
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-48;ch=getchar();}
return x*f;
}
const int N=1e5+10;
int p;
int kase,zs;
struct data{
int a,id,nex,pre;
}s[N];
int n;
int ans[N];
int num[N];
bool cmp(const data &x,const data &y)
{
return x.a>y.a;
}
void dele(int x)//删除当前位置的数
{
s[s[x].pre].nex=s[x].nex;
s[s[x].nex].pre=s[x].pre;
return ;
}
signed main()
{
p=read();
while(p--)
{
kase=read();
n=read();
for(int i=1;i<=n;i++)
{
s[i].a=read();
s[i].id=i;
}
sort(s+1,s+1+n,cmp);
for(int i=1;i<=n;i++)
{
s[i].nex=i+1;
s[i].pre=i-1;
num[s[i].id]=i;
}//常规操作,与邻值查找类似
int mid=(n+1)/2;//当前序列中间位置的数 ,也是最开始总的中位数个数
cout<<kase<<" "<<mid<<endl;
int cnt=0;
for(int i=n;i>=1;i--)//倒着往前
{
if(i%2)//奇数位
{
ans[++cnt]=s[mid].a;//将中位数存起来
if(num[i]>=mid) mid=s[mid].pre;//如果这个即将被删的数在原先中位数的左边,那删掉之后,整个序列的中位数应向前移一个单位
dele(num[i]);//删掉这个数
}
else
{
if(num[i]<=mid) mid=s[mid].nex;//如果这个即将被删的数在原先中位数的右边,那删掉之后,整个序列的中位数应向后移一个单位
dele(num[i]);//删掉这个数
}
}
int k=0;
for(int i=cnt;i>=1;i--)//倒着输出
{
cout<<ans[i]<<" ";
k++;//每输出十个,就换行
if(k%10==0) cout<<endl;
}
if(cnt%10) cout<<endl;//如果超过十个了,也要换行
}
return 0;
} 
京公网安备 11010502036488号