版权声明:欢迎转载 https://blog.csdn.net/suntengnb/article/details/80027441
问题描述:
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.
题目大意:
给出一个序列,输出其子序列
AC代码:
int main()
{
int t;
cin >> t;
while(t--)
{
priority_queue<int,vector<int>,less<int> > pq1;//大顶堆
priority_queue<int,vector<int>,greater<int> > pq2;//小顶堆
int id,n;
cin >> id >> n;
printf("%d %d\n",id,n / 2 + 1);//中位数的总数
int cnt = 0;//每输出10个数换行一次
for(int i = 1; i <= n; ++i)
{
int t;
cin >> t;
if(i % 2 == 1)//如果是第奇数个数
{
pq2.push(t);//加入小顶堆
while(!pq1.empty() && pq1.top() > pq2.top())//维护对顶堆的性质,注意第一次大顶堆为空
{
//交换堆顶元素
int t1 = pq1.top();
pq1.pop();
int t2 = pq2.top();
pq2.pop();
pq1.push(t2);
pq2.push(t1);
}
printf("%d ",pq2.top());//输出小顶堆对顶
cnt++;
if(cnt % 10 == 0)
cout << endl;
}
else//第偶数个数放入大顶度
pq1.push(t);
}
cout << endl;
}
return 0;
}
解决方法:
对于一个序列中的中位数,它左边的数都比它小,右边的数都比它大。比较暴力的想法是对每一个要求的序列都进行一次快排,输出中间的数。这样非常地慢,而且信息过多(升序)是一种浪费,对于左边的数,只要比中位数小就可以了,没必要有序。
根据数学中的如果一个集合A中最小的数比另一个集合B中最大的数大,则A中的所有数大于B中的所有数。
集合中的最大最小数容易让我们联想到堆这种数据结构
最小堆的堆顶要大于最大堆的堆顶,而如果最小堆的大小比最大堆的大小多1的话,最小堆的堆顶就是中位数!
最小堆与最大堆之间的关系在中位数的输出之前维护即可