前言

之前在面试的时候,面试官非常喜欢问:你好,请问在一个很大的数组中怎样快速地找出它的中位数?

当时很迷惑,为什么面试官总喜欢找中位数?后来了解到快速排序算法的思想后,发现如果大概知道待排序数组中位数的大小(或者提前找出中位数),将在数量级上提高快速排序算法的效率,这个后面有空再讲。

如果你想先把数组排序,在找出中间那一个,那就。。。。

大家看到算法一定立刻想到时间复杂度和空间复杂度,这是基本的思维方式。我这里提供两个方法,

  1. 方法一提供代码,可以现场给面试官手撕代码(这就直接发offer了);
  2. 方法二提供思路,只要你说出思路来,已经可以征服面试官了。

1.方法一

方法API:

//这里k任意取,如果k=strlen(s)/2,那么就是寻找中位数
char select(char *s, int k);

上面返回的是char,当然也可以为int.

利用快速排序算法的思想,使用切分法来缩小数组的范围。
这个方法能够在线性时间内解决寻找中位数的问题,神不神奇?

1.1第一步:切分

//将数组切分成s[lo .. i-1], s[i], s[i+1 .. hi];
int partition(char *s, int lo, int hi);

结果:它会将数组 s[lo]s[hi] 重新排列,并返回一个整数j,使得:

  1. s[lo ... j - 1] 小于等于s[j],但是s[lo ... j - 1] 内部并不有序;
  2. s[j + 1 ... hi] 大于等于s[j],但是s[j + 1 ... hi] 内部并不有序;
  3. 返回整数j,下一次使用。
int partition(char *s, int lo, int hi) {//将数组切分成s[lo .. i-1], s[i], s[i+1 .. hi];int i = lo, j = hi + 1;char v = s[lo];//数组第一个元素,作为基准元素while (true) {//扫描左右元素,检查是否需要交换(大于基准元素 和 小于基准元素)while (s[++i] < v) { if (i == hi) { break; } }while (s[--j] > v) { if (j == lo) { break; } }if (i >= j) { break; }char temp = s[i];s[i] = s[j];s[j] = temp;}//将基准元素放回数组中正确的位置char temp = s[lo];s[lo] = s[j];s[j] = temp;//s[lo ..j - 1] <= s[j] <= s[j + 1 ..hi]return j;
}

1.2 第二步:寻找

//这里k任意取,如果k=strlen(s)/2,那么就是寻找中位数
char select(char *s, int k);
  1. 如果k = j,问题就解决了;
  2. 如果k < j,继续切分左子数组(令hi = j - 1);
  3. 如果k > j,继续切分右子数组(令lo = j + 1);
char select(char *s, int k) {int lo = 0, hi = strlen(s) - 1;while (hi > lo) {int j = partition(s, lo, hi);if (j == k) { return s[k]; }else if (j > k) { hi = j - 1; }else if (j < k) { lo = j + 1; }}return s[k];
}

1.3 第三步:完整代码,举例分析

#include<string.h>
#include <stdio.h>
#include <time.h>#define _CRT_SECURE_NO_DEPRECATE;
#define _CRT_SECURE_NO_WARNINGS;int partition(char *s, int lo, int hi);
char select(char *s, int k);
int main()
{int start;start = clock();char s1[] = "abcfed";char s2[] = "bcadfe";char s3[] = "fshskbbsadasdaafsdgfgntyasfafasfahsfkasfapqipowejq1231nkdsk,1213";int k = 5;//这里k任意取,如果k=strlen(s)/2,那么就是寻找中位数char res = select(s1, k);printf("\n");printf("   ");printf("%c",res);printf("\n");getchar();//return 0;}char select(char *s, int k) {int lo = 0, hi = strlen(s) - 1;while (hi > lo) {int j = partition(s, lo, hi);if (j == k) { return s[k]; }else if (j > k) { hi = j - 1; }else if (j < k) { lo = j + 1; }}return s[k];
}int partition(char *s, int lo, int hi) {//将数组切分成s[lo .. i-1], s[i], s[i+1 .. hi];int i = lo, j = hi + 1;char v = s[lo];//数组第一个元素,作为基准元素while (true) {//扫描左右元素,检查是否需要交换(大于基准元素 和 小于基准元素)while (s[++i] < v) { if (i == hi) { break; } }while (s[--j] > v) { if (j == lo) { break; } }if (i >= j) { break; }char temp = s[i];s[i] = s[j];s[j] = temp;}//将基准元素放回数组中正确的位置char temp = s[lo];s[lo] = s[j];s[j] = temp;//s[lo ..j - 1] <= s[j] <= s[j + 1 ..hi]return j;
}

1.4分析

1.假设每次都正好将数组二分,那么总比较次数为: N + N 2 + N 4 + N 8 + . . . ≈ 2 N N+\frac{N}{2}+\frac{N}{4}+\frac{N}{8}+... \approx2N N+2N​+4N​+8N​+...≈2N 式中:N为数组大小。
2.如果 k = N 2 k=\frac{N}{2} k=2N​ ,那么这个代码就是找中位数,当然也可以找任意第几大(小)的数。

2.方法二

方法二也是基于切分的思想,我们想想,加入现在有100G的数据需要你找出中位数。不能依次放到内存中,你怎么办?

基本知识

  1. 我们都知道,数据在硬盘中都是以二进制储存的,也就是11001011这样。
  2. 从左到右依次是最高位到最低位(不考虑符号位),最左边位为1的肯定比最左边为0的大,(100000000000 >
    011111111111111)。

操作步骤

那么我们建立这样的桶,每进来一个数据,我们就放到相应的桶。

如下是取最高的两位,也就是4个桶:四个桶可以代表4个硬盘,内存里面的代码每次将进来的数分到4个桶里。计算每个桶里面数据的个数。初步确定中位数在哪一个桶里,再对那个桶进行一样的分法,是不是很简单。

思维拓展

当然,你也可以建立8个桶,这样步骤更少,也更快:

如果觉得好,请不要忘记点赞。

寻找大数组中位数问题(一)相关推荐

  1. 如何寻找无序数组中的第K大元素?

    如何寻找无序数组中的第K大元素? 有这样一个算法题:有一个无序数组,要求找出数组中的第K大元素.比如给定的无序数组如下所示: 如果k=6,也就是要寻找第6大的元素,很显然,数组中第一大元素是24,第二 ...

  2. LeetCode:Find Peak Element - 寻找一个数组内的顶点

    2019独角兽企业重金招聘Python工程师标准>>> 1.题目名称 Find Peak Element(寻找一个数组内的顶点) 2.题目地址 https://leetcode.co ...

  3. 报名即将截止,中国移动“梧桐杯”大数据应用创新大赛,寻找大数据敢想者!...

    ↑↑↑关注后"星标"Datawhale 每日干货 & 每月组队学习,不错过 Datawhale赛事 主办方:中国移动信息技术中心 也许,你在大数据分析路上踽踽独行 来这里, ...

  4. php in_array 遍历,in_array大数组查询性能问题

    问题 最近在实现一个项目接口的时候发现当数组过大的时候,数据返回的速度有点慢.接口数据返回最长反应时间2s,经过反复调试发现代码段耗时最长的部分在in_array()函数. 解决过程 在stackov ...

  5. php大数组循环嵌套的性能优化

    一.前言 博主最近在用elasticsearch做项目,查出来的数据都是数组,在筛选数据组装数据的时候,难免会碰到循环嵌套的问题.如果两个50000的数组循环嵌套,那实际运算则是50000*50000 ...

  6. java快速寻找一个数组的最大值或最小值, min, max,三种方法

    java 中 寻找一个数组中的最大值或最小,除了自己专门编写一个 min 或 max 函数外,还有几种方式方便使用. 1. 使用 stream 将一个数组放进 stream 里面,然后直接调用 str ...

  7. php 循环大数组 卡死,PHP 大数组循环问题_PHP教程

    小妹刚刚改投PHP门下.领导叫我把这段代码的执行效率优化一下 我现在知道的优化就是小循环外面,好像在这没啥用. 请问各位大侠我该怎么优化ne ? 领导说放内存里什么的. 基本就是2个大数组不停的循环算 ...

  8. pat题解java,1039 到底买不买 (20分) Java题解 PAT (Basic Level) Practice (中文)- 巧妙开大数组减少代码量...

    1039 到底买不买 (20分) 原题链接:传送门 一.题目: 输入样例 1: ppRYYGrrYBR2258 YrR8RrY 输出样例 1: Yes 8 输入样例 2: ppRYYGrrYB225 ...

  9. 一篇文章告诉你如何寻找水王(数组中存在超过一半的数字)

    #include<iostream> using namespace std; //case1 排序后返回数组中间的那个数字O nlogn //case2 hash统计 //case3 顺 ...

最新文章

  1. css 伪元素::after与::before的使用
  2. WebApi2官网学习记录---异常处理
  3. 程序员的工资VS普通人的工资...
  4. Windows上安装JDK
  5. unity(2017.3) C# 常用API
  6. Hibernate-级联操作
  7. 【后两个测试点】地下迷宫探索 (30 分)
  8. 【转】Mac系统中安装homebrew(类似redhat|Centos中的yum;类似Ubuntu中的apt-get)
  9. 基于JS实现新闻列表无缝向上滚动实例代码
  10. pstack: Input/output error failed to read target解决
  11. one hot encoding
  12. 在队列同步器中,同步队列为什么是双向链表,而等待队列是单链表?
  13. SSH/SSH客户端介绍、利用SSH访问linux、SSH跟telnet区别
  14. 宏脉系统怎么改服务器地址,宏脉系统使用手册大全.doc
  15. 基于阿里云的基础架构设施保障(一)IAAS云计算
  16. 2016年美团校园招聘数据开发工程师笔试编程题
  17. 2毫秒c51汇编语言延时函数,单片机精确毫秒延时函数
  18. spoolsv病毒清除方法
  19. OpenCV如何进行图像的平滑和锐化处理?
  20. linux_添加一个普通用户

热门文章

  1. 【开发教程5】开源蓝牙心率防水运动手环-电池电量检测
  2. 工商银行服务态度极其恶劣!!
  3. flac格式如何转mp3,3种简单方法值得收藏
  4. 学校无盘服务器带机量50台要求,如何解决无盘回写压力,提高服务器带机量?...
  5. EXCEL中应用Smart art,图形中打字卡顿如何解决?
  6. 龙之气息服务器维护,龙之气息攻略大全 龙之气息新手少走弯路攻略
  7. qrcodejs2下载二维码无白边扫码识别不出来
  8. 【池化技术】池化技术基础和原理
  9. Vue3电影中后台开发纪实(二):导航搭建
  10. 如何在Altium Designer设计标志图案