中位数

中位数

洛谷P1168 中位数

前言:

被教练当作数据结构和STL的阶段性测试题,考试时候觉得sort会爆超多(打脸啊,sort可是40ptsQAQ)就没写

然后顺利的敲了个暴力,20pts滚粗(不过我好像也就编了几分钟...)

当时的思路就是开两层循环,用一个小根堆来做,暴力嘛,能骗多少骗多少


题目简述:

给你长度为n的序列Ai,(n≤10^5,Ai≤10^9)

要求输出奇数个数的中位数(即输出前1、3、5、7···个数的中位数)


解题思路:

  • STL:vector+lower_bound函数
    (这大概是这题最短的代码了吧?)

因为每次插入后再排序肯定会超时的,所以我们在插入前就进行排序(并不是每次从头排序哦!)

解决了排序,就能让之前在vector中的元素保持单调性,那我们怎么知道当前的元素x该插入什么位置呢?

如果你对STL函数库足够熟悉的话,那么就能想到,STL中有现成的函数可以帮助我们实现这个期望:lower_bound函数

scanf("%d",&x);
a.insert(lower_bound(a.begin(),a.end(),x),x); //lower_bound返回的是在[a.begin(),a.end())这个区间内第一个大于等于x的元素的迭代器

这里的a是一个vector<int>类型的
补充一下:insert(it,x)用来向vector的任意迭代器it处插入一个元素想,时间复杂度为O(N)

完整代码就不用放了吧?就是边输入边插入,遇到奇数个元素就输出中位数即可

  • STL:大根堆&小根堆

(这个应该算是解决这道题最常见的思路了)

要维护中位数,那我们整两个堆,一个大根堆存放小于等于中位数的数,一个小根堆存放大于中位数的数

很显然,小根堆的堆顶是第一个大于mid的数,大根堆堆顶是第一个小于等于mid的数字(我们设mid为中位数,mid初始就是第一个元素)

scanf("%d",&mid);  //第一个数直接输入mid即可
printf("%d
",mid);  //第一个也直接输出

每一次输入一个元素x,我们就判断该放入哪个堆:

scanf("%d",&x);
if(x>mid) shans.push(x);  //大于中间值,进入小根堆 
else shan.push(x);  //否则进入大根堆 

如果遇到奇数个元素,我们就先维护两个堆的元素个数相同(因为只有两个堆的元素个数相同,那mid才能是中位数)

维护元素个数很简单:如果大根堆多于小根堆,就把当前mid存入小根堆,将大根堆对顶赋给mid再删除堆顶,直到元素个数相同(小根堆多的话反过来就是了)

if(i%2==1) {  //奇数个数就输出
   while(shan.size()!=shans.size()) {  //维护两个堆的元素个数相等,保证mid始终是中位数
	if(shan.size()>shans.size()) {
	   shans.push(mid);
	   mid=shan.top();
	   shan.pop();
	} 
        else {
	   shan.push(mid);
	   mid=shans.top();
	   shans.pop();
	}
    }
    printf("%d
",mid);
}

完整Code:

如下是第二种思路的代码

#include <bits/stdc++.h>
using namespace std;
int n,x,mid;
priority_queue<int,vector<int>,less<int> > shan; //大根堆存小于等于mid的数 
priority_queue<int,vector<int>,greater<int> > shans;  //小根堆存大于mid的数 
//小根堆的堆顶是第一个大于mid的数,大根堆堆顶是第一个小于等于mid的数字

int main() {
	scanf("%d",&n);
	scanf("%d",&mid);  //第一个数直接输入mid即可 
	printf("%d
",mid); 
	for(register int i=2;i<=n;i++) {
		scanf("%d",&x);
		if(x>mid) shans.push(x);  //大于中间值,进入小根堆 
		else shan.push(x);  //否则进入大根堆 
		if(i%2==1) {  //奇数个数就输出 
			while(shan.size()!=shans.size()) {  //维护两个堆的元素个数相等,保证mid始终是中位数 
				if(shan.size()>shans.size()) {
					shans.push(mid);
					mid=shan.top();
					shan.pop();
				}
				else {
					shan.push(mid);
					mid=shans.top();
					shans.pop();
				}
			}
			printf("%d
",mid);
		}
	}
	return 0;
} 

后序:

还能用平衡树做,但我不配啊(太菜)

所以在这里只是提一下这种做法,大家可以去看看其他dalao的博客

最后:第一种超短代码的思路来自:deco大佬的题解 感谢orz


原文地址:https://www.cnblogs.com/Eleven-Qian-Shan/p/13162616.html