云漫圈 | 寻找无序数组的第k大元素

戳蓝字“CSDN云计算”关注我们哦!


者:小灰

来源:程序员小灰

   本期封面作者:泰勒太乐

         

640?wx_fmt=jpeg

640?wx_fmt=jpeg


—————  第二天  —————


640?wx_fmt=jpeg

640?wx_fmt=jpeg


640?wx_fmt=jpeg


题目是什么意思呢?比如给定的无序数组如下:


640?wx_fmt=png


如果 k=6,也就是要寻找第6大的元素,这个元素是哪一个呢?


显然,数组中第一大的元素是24,第二大的元素是20,第三大的元素是17 ...... 第6大的元素是9


640?wx_fmt=png

640?wx_fmt=jpeg

640?wx_fmt=jpeg


方法一:排序法

这是最容易想到的方法,先把无序数组从大到小进行排序,排序后的第k个元素,自然就是数组中的第k大元素。


640?wx_fmt=png



640?wx_fmt=jpeg

640?wx_fmt=jpeg


640?wx_fmt=jpeg


方法二:插入法

维护一个长度为k的数组A的有序数组,用于存储已知的k个较大的元素。

接下来遍历原数组,每遍历到一个元素,和数组A中最小的元素相比较,如果小于等于数组A的最小元素,继续遍历;如果大于数组A的最小元素,则插入到数组A中,并把曾经的最小元素“挤出去”。


比如k=3,先把最左侧的7,5,15三个数有序放入数组A当中,代表当前最大的三个数。

640?wx_fmt=png


这时候,遍历到3, 由于3<5,继续遍历。

640?wx_fmt=png


接下来遍历到17,由于17>5,插入到数组A的合适位置,类似于插入排序,并把原先最小的元素5“挤出去”。

640?wx_fmt=png


继续遍历原数组,一直遍历到数组的最后一个元素......


最终,数组A中存储的元素是24,20,17,代表着整个数组中最大的3个元素。此时数组A中的最小的元素17就是我们要寻找的第k大元素。

640?wx_fmt=png


640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg



————————————



640?wx_fmt=jpeg

640?wx_fmt=jpeg


640?wx_fmt=jpeg


640?wx_fmt=jpeg



什么是二叉堆?不太了解的小伙伴可以先看看这一篇:漫画:什么是二叉堆?


简而言之,二叉堆是一种特殊的完全二叉树,它包含大顶堆和小顶堆两种形式。


其中小顶堆的特点,是每一个父节点都大于等于自己的子节点。要解决这个算法题,我们可以利用小顶堆的特性。


640?wx_fmt=jpeg

640?wx_fmt=jpeg



方法三:小顶堆法

维护一个容量为k的小顶堆,堆中的k个节点代表着当前最大的k个元素,而堆顶显然是这k个元素中的最小值

遍历原数组,每遍历一个元素,就和堆顶比较,如果当前元素小于等于堆顶,则继续遍历;如果元素大于堆顶,则把当前元素放在堆顶位置,并调整二叉堆(下沉操作)。

遍历结束后,堆顶就是数组的最大k个元素中的最小值,也就是第k大元素


假设k=5,具体的执行步骤如下:


1.把数组的前k个元素构建成堆。


640?wx_fmt=png


2.继续遍历数组,和堆顶比较,如果小于等于堆顶,则继续遍历;如果大于堆顶,则取代堆顶元素并调整堆。


遍历到元素2,由于 2<3,所以继续遍历。


640?wx_fmt=png


遍历到元素20,由于 20>3,20取代堆顶位置,并调整堆。


640?wx_fmt=png



640?wx_fmt=png


遍历到元素24,由于 24>5,24取代堆顶位置,并调整堆。


640?wx_fmt=png



640?wx_fmt=png


以此类推,我们一个一个遍历元素,当遍历到最后一个元素8的时候,小顶堆的情况如下:


640?wx_fmt=png


3.此时的堆顶,就是堆中的最小值,也就是数组中的第k大元素。


640?wx_fmt=png



这个方法的时间复杂度是多少呢?


1.构建堆的时间复杂度是 O(k)

2.遍历剩余数组的时间复杂度是O(n-k)

3.每次调整堆的时间复杂度是 O(logk)


其中2和3是嵌套关系,1和2,3是并列关系,所以总的最坏时间复杂度是O((n-k)logk + k)。当k远小于n的情况下,也可以近似地认为是O(nlogk)



这个方法的空间复杂度是多少呢?


刚才我们在详细步骤中把二叉堆单独拿出来演示,是为了便于理解。但如果允许改变原数组的话,我们可以把数组的前k个元素“原地交换”来构建成二叉堆,这样就免去了开辟额外的存储空间。


因此,方法的空间复杂度是O(1)


640?wx_fmt=jpeg

640?wx_fmt=jpeg


  1. /**

  2. * 寻找第k大的元素

  3. * @param array  待调整的堆

  4. * @param k  第几大

  5. */

  6. public static int findNumberK(int[] array, int k){

  7.    //1.用前k个元素构建小顶堆

  8.    buildHeap(array, k);

  9.    //2.继续遍历数组,和堆顶比较

  10.    for(int i=k; i<array.length;i++){

  11.        if(array[i] > array[0]){

  12.            array[0] = array[i];

  13.            downAdjust(array, 0, k);

  14.        }

  15.    }

  16.    //3.返回堆顶元素

  17.    return array[0];

  18. }


  19. /**

  20. * 构建堆

  21. * @param array  待调整的堆

  22. * @param length  堆的有效大小

  23. */

  24. private static void buildHeap(int[] array, int length) {

  25.    // 从最后一个非叶子节点开始,依次下沉调整

  26.    for (int i = (length-2)/2; i >= 0; i--) {

  27.        downAdjust(array, i, length);

  28.    }

  29. }


  30. /**

  31. * 下沉调整

  32. * @param array     待调整的堆

  33. * @param index    要下沉的节点

  34. * @param length    堆的有效大小

  35. */

  36. private static void downAdjust(int[] array, int index, int length) {

  37.    // temp保存父节点值,用于最后的赋值

  38.    int temp = array[index];

  39.    int childIndex = 2 * index + 1;

  40.    while (childIndex < length) {

  41.        // 如果有右孩子,且右孩子小于左孩子的值,则定位到右孩子

  42.        if (childIndex + 1 < length && array[childIndex + 1] < array[childIndex]) {

  43.            childIndex++;

  44.        }

  45.        // 如果父节点小于任何一个孩子的值,直接跳出

  46.        if (temp <= array[childIndex])

  47.            break;

  48.        //无需真正交换,单向赋值即可

  49.        array[index] = array[childIndex];

  50.        index = childIndex;

  51.        childIndex = 2 * childIndex + 1;

  52.    }

  53.    array[index] = temp;

  54. }



  55. public static void main(String[] args) {

  56.    int[] array = new int[] {7,5,15,3,17,2,20,24,1,9,12,8};

  57.    System.out.println(findNumberK(array, 5));

  58. }


640?wx_fmt=jpeg


方法四:分治法

大家都了解快速排序,快速排序利用分治法,每一次把数组分成较大和较小的两部分。

我们在寻找第k大元素的时候,也可以利用这个思路,以某个元素A为基准,把大于于A的元素都交换到数组左边,小于A的元素都交换到数组右边。


比如我们选择以元素7作为基准,把数组分成了左侧较大,右侧较小的两个区域,交换结果如下:


640?wx_fmt=png


包括元素7在内的较大元素有8个,但我们的k=5,显然较大元素的数目过多了。于是我们在较大元素的区域继续分治,这次以元素12位基准:


640?wx_fmt=png


这样一来,包括元素12在内的较大元素有5个,正好和k相等。所以,基准元素12就是我们所求的。


这就是分治法的大体思想,这种方法的时间复杂度甚至优于小顶堆法,可以达到O(n)。有兴趣的小伙伴可以尝试用代码实现一下。


640?wx_fmt=jpeg


1.微信群:

添加小编微信:color_ld,备注“进群+姓名+公司职位”即可,加入【云计算学习交流群】,和志同道合的朋友们共同打卡学习!


2.征稿:

投稿邮箱:liudan@csdn.net;微信号:color_ld。请备注投稿+姓名+公司职位。



推荐阅读

  • 有问有答 | 分布式服务框架精华问答

  • 深入理解与应用Hadoop中的MapReduce

  • 等了20年的物联网,这次真的会成功吗?

  • 云要闻 | 腾讯在华南建云计算基地;致敬Larry Roberts

  • 网友们票选的2018 Best Paper,你pick谁?

  • 程序员有话说 | 大专生毕业 6 年月薪 3W+:不从众也不普通

  • Windows 10 终于干掉了 Windows 7!

  • 比特币拒绝第340次“被死亡”


程序员抢票的正确姿势 ↓↓交朋友还能抢票?


640?wx_fmt=jpeg

为交流学习,请备注抢票+姓名+公司职位


640?wx_fmt=gif点击“阅读原文”,打开 CSDN App 阅读更贴心!

640?wx_fmt=png喜欢就点击“好看”吧!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/524990.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

继承之详细讲解

代码结构 package com.wuming.oop2.demo05; //person 人 父类 public class Person {//继承:java只有单继承&#xff0c;没有多继承&#xff0c;extends修饰public int money10_0000_0000;private int money120;public int getMoney1() {return money1;}public void setM…

BugkuCTF-MISC题乌云邀请码

下载文件&#xff0c;解压后得到一张图片 方法一&#xff1a; 通过zsteg直接得到flag 方法二&#xff1a; 放入Stegsolve查看 发现红绿蓝plane0 的最上边都有一排小黑点儿&#xff0c;很可疑 选择Analyse 的Data Extract进行分析 勾选红绿蓝的0层&#xff0c;选BGR模式&…

趣挨踢 | 关于遗留代码的那些事儿

戳蓝字“CSDN云计算”关注我们哦&#xff01;来自&#xff1a;程序员最幽默&#xff08;ID&#xff1a;humor1024&#xff09;【1】当我不小心打开了遗留代码&#xff0c;世界从我眼前消失了。【2】当我试图破译遗留代码的时候【3】当我尝试修复遗留代码&#xff0c;却永远找不…

云计算演进历程与模式 - 初识云计算知识专栏(2)

戳蓝字“CSDN云计算”关注我们哦&#xff01;云计算演进历程云计算产生背景云计算的产生是需求推动、技术进步、商业模式转变共同促进的结果。需求推动指的是政企客户低成本且高性能的信息化需求&#xff1b;人用户的互联网、移动互联网应用需求强烈&#xff0c;追求更好用户体…

BugkuCTF-MISC题细心的大象

下载文件file.zip 直接解压出错&#xff0c;通过binwalk -e file.zip分离出文件夹_file.zip.extracted 得到一张图片&#xff0c;通过binwalk -e 1.jpg分离出文件夹_1.jpg.extracted 得到.rar压缩包&#xff0c;打开需要密码&#xff0c;通过爆破找不到密码 查看1.jpg图片属性&…

BugkuCTF-MISC题想蹭网先解开密码

下载文件wifi.cap 先通过crunch命令先生成字典 crunch 11 11 -t 1391040%%%% -o password.txt 输入aircrack-ng wifi.cap 输入3&#xff0c;因为第三个存在握手包 输入aircrack-ng -e D-Link_DIR-600A -b BC:F6:85:9E:4E:A3 -w /root/文档/CTF题目/CTF02/MISC/想蹭网先解开密…

云要闻 | 华为助力5G;青云云资源价格全面下调;神州数码签订云计算服务合同

戳蓝字“CSDN云计算”关注我们哦&#xff01;Hello&#xff0c;everyone&#xff1a;1月7日&#xff0c;星期一CSDN云要闻时间&#xff1a;嗨&#xff0c;大家好&#xff0c;偶是“CSDN 云计算”微信公众号新晋成员一枚&#xff0c;人称“要闻君”。精神满满的周一&#xff0c;…

BugkuCTF-MISC题旋转跳跃

先下载解压&#xff0c;尝试播放 既然是mp3&#xff0c;那么先尝试拉入Audacity 没发现啥&#xff0c;仔细看了看题目注释&#xff0c;发现给了个KEY 打开mp3stego-gui的根目录 在终端输入wine Decode.exe -X -P syclovergeek sycgeek-mp3.mp3 (wine为在linux打开exe文件) 会…

有问有答 | 算法和数据结构精华问答

戳蓝字“CSDN云计算”关注我们哦&#xff01;所有的算法&#xff0c;乃至数学在实际运用中都是要根据不同的数据来选择不同的方法&#xff0c;所以一般学习过算法和数据结构的人都会越发的认识到&#xff0c;数据才是程序的中心&#xff0c;只有找到了一个组织数据的最佳方式&a…

BugkuCTF-MISC题一切有为法如梦幻泡影

下载文件 从Zero.png里foremost分离出一个压缩包&#xff0c;解压得到问.png 没有得到 《察》.zip 密码的提示&#xff0c;所以爆破得到密码42&#xff0c;解压得到这两个文件 先分析one.png&#xff0c;foremost分离出压缩包&#xff0c;解压得到感.png&#xff0c;同样也没…

细数阿里达摩院2019年的十个Flag

戳蓝字“CSDN云计算”关注我们哦&#xff01;来自&#xff1a;人工智能与大数据作者&#xff1a;AI小哥1月2日&#xff0c;阿里达摩院发布《2019十大科技趋势》&#xff0c;在未来的一年&#xff0c;科技领域究竟会再次迎来春天&#xff0c;还是继续在寒冬中前行&#xff0c;达…

BugkuCTF-MISC题隐写

隐写&#xff1a; TeakPNG打开图片 在010editor里修改CRC 打开图片发现没有flag 在TeakPNG将420改为500&#xff0c;弹出flag

云头条 |华为发布鲲鹏920;高通新推智能座舱芯片;Github重磅更新

戳蓝字“CSDN云计算”关注我们哦&#xff01;嗨&#xff0c;大家好&#xff0c;偶是“CSDN 云计算”微信公众号新晋成员一枚“头条君”。第一次和大家见面&#xff0c;先做个自我介绍吧&#xff0c;头条君带来的【云头条】特别栏目&#xff0c;会在未来的日子里&#xff0c;无论…

BugkuCTF-MISC题隐写2

下载文件welcome.jpg 通过binwalk分离出文件&#xff0c;_welcome.jpg.extracted文件夹 爆破压缩包&#xff0c;得到解压密码为871 通过010editor打开解压图片&#xff0c;得到base64编码 解码即可

C语言 二维数组行数和列数计算 - C语言零基础入门教程

目录 一.计算一维数组长度二.计算二维数组长度 1.二维数组行数2.二维数组列数3.二维数组的元素个数 二维数组行数 * 二维数组列数 三.猜你喜欢 零基础 C/C 学习路线推荐 : C/C 学习目录 >> C 语言基础入门 一.计算一维数组长度 在前面很多文章都介绍了关于普通数组计算…

Istio调用链埋点原理剖析—是否真的“零修改”分享实录

戳蓝字“CSDN云计算”关注我们哦&#xff01;来自&#xff1a;容器魔方作者&#xff1a; idouba本文整理自华为Cloud BU技术专家在K8S技术社上关于Istio调用链的分享。前言大家好&#xff0c;我是idouba&#xff0c;来自华为Cloud BU&#xff0c;当前在做Istio服务网格在华为云…

C语言 二维数组遍历 - C语言零基础入门教程

目录 一.计算一维数组长度二.计算二维数组长度 1.二维数组行数2.二维数组列数3.二维数组的元素个数 二维数组行数 * 二维数组列数 三.猜你喜欢 零基础 C/C 学习路线推荐 : C/C 学习目录 >> C 语言基础入门 一.计算一维数组长度 对于 type array[A]形式的数组&#xff…

有问有答 | 你真的理解微服务架构吗?

戳蓝字“CSDN云计算”关注我们哦&#xff01;过去几年来&#xff0c;“微服务架构”这个术语出现了&#xff0c;它描述了一种将软件应用程序设计为可独立部署的服务套件的特定方式。近几年微服务吵的也比较火&#xff0c;那么为什么微服务会受到这么多的关注&#xff1f;今天&a…

BugkuCTF-MISC题有黑白棋的棋盘

下载了三个加密的zip压缩文件 其里一个名为4easynum.zip&#xff0c;很明显提示密码是四位数&#xff0c;爆破得到7760 打开得到一个图片和文本&#xff1a; 图片解出来是棋盘的压缩包密码 棋盘是flag的密码 题目描述也提示了&#xff0c;这个是古精灵语密码 对照得到棋盘的压…

有问有答 | AWS使用精华问答,带您开启 AWS 上的云计算之旅!

戳蓝字“CSDN云计算”关注我们哦&#xff01;AWS作为业界领先的云服务提供商&#xff0c;提供多种多样的高可靠性服务。那么究竟该如何使用AWS呢&#xff1f;今天的有问有答栏目&#xff0c;将带您开启 AWS 上的云计算之旅&#xff01;1Q&#xff1a;请问RDS相较自建MySQL on E…