题目描述
链接: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; }