码迷,mamicode.com
首页 > 其他好文 > 详细

P1168 中位数

时间:2020-06-22 21:18:49      阅读:79      评论:0      收藏:0      [点我收藏+]

标签:turn   时间   stdout   clu   位置   查找   ble   return   二分   

题目链接

题意:

? 对于给定序列,求出前奇数个元素的中位数。

思路:

? 既然要求中位数,根据题目一看,有点类似与滑动窗口那道题,但想了想,不一样。暴力维护队列,O($n^2$)的时间复杂度面对十万肯定会爆,再试试之前学过的STL模板的优先队列和set是否可以,发现两者对于中位数的查找似乎显得力不从心,想到的只剩下二分了。

为什么考虑二分?

? 我们学过插入排序来维护序列,当一个元素加入序列时,将其插入它的理想位置,就像平时斗地主搓麻将理牌一样,可以有效的动态维护有序序列,二分优化后的时间复杂度为O($nlog_2(n)$)能够满足n=100000的要求。

大致流程:

  1. 对于当前元素,二分找到它的插入位置;
  2. 将其插入序列;
  3. 如果是第奇数个,输出序列中间的数;

实现中的小技巧:

? 我们需要一个既可以高效率实现插入又可以高效率访问中间元素的容器来存储序列,这种既满足链表,又满足数组的特征的容器是什么?vector!(学前误认一无是处,学后方知相见恨晚)

100分代码:

#include <bits/stdc++.h>
using namespace std;
int n;
vector<int> a;
inline int place(int l,int r,int v){
	if(l>r)return l;
	if(l==r){
		return l;
	}
	if(a[l]==v)return l;
	int mid=(l+r)/2;
	if(v<a[mid]){
		return place(l,mid-1,v);
	}
	if(v==a[mid]){
		return mid;
	}
	if(v>a[mid]){
		return place(mid+1,r,v);
	}
}
int main() {
	//freopen("in.txt","r",stdin);
	//freopen("out.txt","w",stdout);
	scanf("%d",&n);
	a.push_back(-1);
	for(register int i=1;i<=n;i++){
		int x;
		scanf("%d",&x);
		int ne=place(0,i-1,x);
		while(x<=a[ne-1]&&ne>=1)ne--;//a[ne]<x
		while(a[ne]<x&&ne<a.size())ne++;
		//cout<<ne<<endl;
		vector<int>::iterator it=a.begin()+ne;//a[*it]<=x<a[*it+1]
		//while(a[*it]>x)it++;
		a.insert(it,x);
		//for(int j=0;j<a.size();j++)cout<<a[j]<<‘ ‘;
		//cout<<endl;
		if(i%2==1){
			printf("%d\n",a[(i+1)/2]);
		}
	}
	return 0;
}

? 注:程序本身是考场上胡乱打出的非完全体,所以bug比较多,代码中可以看出加了许多“补丁”。还有,注意不要用cin,cout,会超时等等,还有很多小细节,可以自行去挖掘。

另外几种可行的思路:lower_bound(),堆,平衡树。

P1168 中位数

标签:turn   时间   stdout   clu   位置   查找   ble   return   二分   

原文地址:https://www.cnblogs.com/returnG/p/13178978.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!