[LintCode] Median(期望时间复杂度O(n)求中位数)

 1 class Solution {
 2 public:
 3     /**
 4      * @param nums: A list of integers.
 5      * @return: An integer denotes the middle number of the array.
 6      */
 7     void swap(vector<int> &v, int i, int j)
 8     {
 9         int tmp = v[i];
10         v[i] = v[j];
11         v[j] = tmp;
12     }
13     int getMedian(vector<int> &v, int left, int right)
14     {
15         if(left<right)
16         {
17             int i = left-1, j = left;
18             for(; j<right;  ++j)
19             {
20                 if(v[j]<v[right])
21                 {
22                     ++i;
23                     swap(v, i, j);
24                 }
25             }
26             swap(v, i+1, right);
27             int sz = v.size();
28             if((sz-1)/2==i+1) return v[i+1];
29             else if((sz-1)/2<=i)  return getMedian(v, left, i);
30             else    return getMedian(v, i+2, right);
31         }
32         else    return v[left];
33     }
34     int median(vector<int> &v) {
35         // write your code here
36         return getMedian(v, 0, v.size()-1);
37     }
38 };

主要利用快排递归划分的思想,可以在期望复杂度为O(n)的条件下求第k大数。快排的期望复杂度为O(nlogn),因为快排会递归处理划分的两边,而求第k大数则只需要处理划分的一边,其期望复杂度将是O(n)。详细的证明见《算法导论》。

我们可以这样粗略的思考:

假设我们的数据足够的随机,每次划分都在数据序列的中间位置,那么第一次划分我们需要遍历约n个数,第二次需要遍历约n/2个数,...,这样递归下去,最后:n+n/2+n/(2^2)+n/(2^3)+...+n/(2^k)+... = (1+1/2+1/(2^2)+1/(2^3)+...+1/(2^k)+...)*n, 当k趋于无穷大的时候,上式的极限为2n。

时间: 2024-08-04 22:25:20

[LintCode] Median(期望时间复杂度O(n)求中位数)的相关文章

[LintCode] Majority Number(以时间复杂度O(n)求主元素)

一个数据序列的主元素,是指序列中出现次数超过序列长度一半的元素. 法1(期望时间复杂度为O(n)): 由于主元素出现次数超过序列长度的一半,因此,主元素一定是中位数.可以利用递归划分求中位数的方法,期望时间复杂度为O(n). 法2: 显然,如果一个序列存在主元素,那么我们去掉序列中不同的两个数,剩下序列的主元素和原序列的主元素相同. 具体算法操作:记录两个量,当前元素x,计数cnt.初始化cnt为0:然后遍历序列,若cnt为0,则将x设为当前元素并将cnt置为1,否则,若当前元素和x相同,那么c

URAL 1306 - Sequence Median 小内存求中位数

[题意]给出n(1~250000)个数(int以内),求中位数 [题解]一开始直接sort,发现MLE,才发现内存限制1024k,那么就不能开int[250000]的数组了(4*250000=1,000,000大约就是1M内存). 后来发现可以使用长度为n/2+1的优先队列,即包含前一半的数以及中位数,其他数在读入的时候就剔除,这样可以省一半的空间. 1 #include<bits/stdc++.h> 2 #define eps 1e-9 3 #define FOR(i,j,k) for(in

POJ 3784 Running Median 动态求中位数 堆

题意. 1000个case 每个case 输入若干个数,对第k个输入,如果k为奇数,则输出前k个数的中位数 那么这就是动态求中位数了 实现的思路也比较简洁 用两个堆, 大顶堆和小顶堆 每次输入一个数,如果这个数比当前的中位数大,就存入小顶堆中,  否则就存入大顶堆. 然后调整, 小顶堆元素的个数要等于大顶堆的元素个数,或者比其多1. 如果小顶堆的元素太多,就塞到大顶堆里,反之亦然 这样一来就会发现.小顶堆的元素比所有大顶堆的元素都大, 而且小顶堆的堆顶就是中位数. 那么怎么样才能想到这样一个思路

LeetCode题目----求中位数---标签:Array

题目难度---困难 题目要求: 给定两个大小为 m 和 n 的有序数组 nums1 和 nums2 . 请找出这两个有序数组的中位数.要求算法的时间复杂度为 O(log (m+n)) . 思路:第一眼看到题目两个数组求中位数,看似很复杂,但是仔细一想,两个数组合在一块不久行了?然后合并后的数组给他排序,进而判断是奇数位数组还是偶数位数组 ok!代码奉上: public static double findMedianSortedArrays(int[] nums1, int[] nums2) {

POJ 2388 Who&#39;s in the Middle(水~奇数个数排序求中位数)

题目链接:http://poj.org/problem?id=2388 题目大意: 奇数个数排序求中位数 解题思路:看代码吧! AC Code: 1 #include<stdio.h> 2 #include<algorithm> 3 using namespace std; 4 int main() 5 { 6 int n; 7 while(scanf("%d",&n)!=EOF) 8 { 9 int na[n+1]; 10 for(int i=0; i

求中位数

求中位数 题目描述 输入n和n个数,求大于中位数的数据个数.(n小于50) 中位数是把一列数从小到大排列后,中间的那个数!如果那一列数是偶数,就取中间两个数的平均数! 例如: 第1组数:1.2.3.6.7的中位数是3. 第2组数:1.2.3.5的中位数是2.5. 输入描述 输入正整数n和n个实数 输出描述 1.输出中位数保留小数1位.中位数输出占一行. 2.输出大于中位数的数据个数占一行. 样例输入 4 1 2 3 5 样例输出 2.5 2

线性求中位数 poj2388

在做uva11300时,遇到了n < 1000 000的中位数,就看了一下线性求中位数. 和快排的思想很像,同理,线性求第k大数,算法如下: ①以某个数x将一段数组分成两部分,比x小的放在左边,比x大的放在右边 ②如果x刚好是出于要找的位置的,直接返回 ③如果在x的左边,则递归在x的右边找 ④如果在x的右边,则递归在x的左边找 代码如下: 1 /*=============================================================== 2 * Copyrig

双堆求中位数

堆 堆的动态创建与删除可参考 http://www.java3z.com/cwbwebhome/article/article1/1362.html?id=4745,此处不再赘述. 双堆求中位数 算法描述: 1.创建两个堆(一个小根堆.一个大根堆),堆大小至少为给定数据个数的一半,向上取整: 2.假定变量mid用来保存中位数,取定第一个元素,赋值给mid,即作为初始的中位数: 3.依次遍历后面的每一个数据,如果比mid小,则插入大根堆:否则插入小根堆: 4.如果大根堆和小根堆上的数据个数相差为2

在线求中位数

在线求第k个数做得多了,在线求中位数也是用堆,一个最大堆,一个最小堆. 思想大概是这样子的: 一个最大堆,一个最小堆,最大堆对应于前n/(n+1)个数,最小堆对应于后n/n+1个数:假设最大堆堆项元素为n1, 最小堆堆顶为n2, 则n1 <= n2; 确保两个堆的大小最多只差1. 设最大堆大小为s1, 最小堆大小为s2,则abs(s1-s2) <= 1: 对于新来的数m,分情况调整: 如果s1== s2, 那么:如果m<= n2, m插入到最大堆,s1= s1+1; 否则插入到最小堆,s