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

作者:小灰

来源:程序员小灰

本期封面作者:泰勒太乐

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

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

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

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

方法一:排序法

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

方法二:插入法

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

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

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

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

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

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

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

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

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

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

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

方法三:小顶堆法

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

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

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

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

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

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

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

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

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

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

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

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

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)

/**

* 寻找第k大的元素

* @param array  待调整的堆

* @param k  第几大

*/

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

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

   buildHeap(array, k);

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

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

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

           array[0] = array[i];

           downAdjust(array, 0, k);

       }

   }

   //3.返回堆顶元素

   return array[0];

}

/**

* 构建堆

* @param array  待调整的堆

* @param length  堆的有效大小

*/

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

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

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

       downAdjust(array, i, length);

   }

}

/**

* 下沉调整

* @param array     待调整的堆

* @param index    要下沉的节点

* @param length    堆的有效大小

*/

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

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

   int temp = array[index];

   int childIndex = 2 * index + 1;

   while (childIndex < length) {

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

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

           childIndex++;

       }

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

       if (temp <= array[childIndex])

           break;

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

       array[index] = array[childIndex];

       index = childIndex;

       childIndex = 2 * childIndex + 1;

   }

   array[index] = temp;

}

public static void main(String[] args) {

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

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

}

方法四:分治法

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

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

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

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

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

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

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次“被死亡”

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

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

点击“阅读原文”,打开 CSDN App 阅读更贴心!

喜欢就点击“好看”吧!

从当前元素继续寻找_云漫圈 | 寻找无序数组的第k大元素相关推荐

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

    戳蓝字"CSDN云计算"关注我们哦! 作者:小灰 来源:程序员小灰 本期封面作者:泰勒太乐 -----  第二天  ----- 题目是什么意思呢?比如给定的无序数组如下: 如果 k ...

  2. 在一个无序的int数组上构建一个最小堆的时间复杂度_漫画:寻找无序数组的第k大元素(修订版)...

    ----- 第二天 ----- 题目是什么意思呢?比如给定的无序数组如下: 如果 k=6,也就是要寻找第6大的元素,这个元素是哪一个呢? 显然,数组中第一大的元素是24,第二大的元素是20,第三大的元 ...

  3. 数组中的元素赋值给元素_漫画:寻找无序数组的第k大元素

    本期封面作者:泰勒太乐 -----  第二天  ----- 题目是什么意思呢?比如给定的无序数组如下: 如果 k=6,也就是要寻找第6大的元素,这个元素是哪一个呢? 显然,数组中第一大的元素是24,第 ...

  4. 遍历数组是什么意思_漫画:寻找无序数组的第k大元素(修订版)

    ----- 第二天 ----- 题目是什么意思呢?比如给定的无序数组如下: 如果 k=6,也就是要寻找第6大的元素,这个元素是哪一个呢? 显然,数组中第一大的元素是24,第二大的元素是20,第三大的元 ...

  5. 数组中第K大元素(java多种方式实现)

    题目描述: Leetcode215题:在未排序的数组中找到第 k 个最大的元素.请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素. 示例 1: 输入: [3,2,1,5 ...

  6. python 无序列表中第k大元素_查询无序列表中第K小元素

    当需要在无需列表中寻找第k小的元素时,一个显然的方法是将所有数据进行排序,然后检索k个元素.这种方法的运行时间为O(n log(n)). 无序列表调用分区函数将自身分解成两个子表,其长度为i和n-i. ...

  7. 寻找无序数组中第k大的数

    对于一个无序的数组,怎样找到其中第k大的数呢?下面总结几种方法. 1.直接排序法 使用常见的归并排序.堆排序等算法对数组进行排序,然后找到第k大的数.排序算法的时间复杂度为O(nlogn),所以算法总 ...

  8. python 无序列表中第k大元素_Python要求O(n)复杂度求无序列表中第K的大元素实例...

    昨天面试上来就是一个算法,平时基本的算法还行,结果变个法就不会了...感觉应该刷一波Leecode冷静下...今天抽空看下. 题目就是要求O(n)复杂度求无序列表中第K的大元素 如果没有复杂度的限制很 ...

  9. 无序数组求第k大的数 python_【python刷题】寻找数组中第K大/小的数

    使用堆 import heapq def findKthLargest(nums, k): stack = [] for num in nums: heapq.heappush(stack, num) ...

最新文章

  1. The ECDSA host key for XXX has changed
  2. python介绍和用途-python数据类型介绍与使用
  3. 2021-01-07 python opencv实现车牌识别 颜色定位
  4. 计算机硬件Word,[计算机硬件及网络]word的操作.doc
  5. 【Oracle】【日期、时间】 date与数字时间戳互转
  6. 210106阶段三 文件I/O
  7. C语言实现下载网页的方法【原创】
  8. 使用JQuery快速高效制作网页交互特效 第十一章 蔚蓝网项目
  9. 系统封装教程---之几种常用封装工具和驱动包的简单介绍
  10. navigateTo和navigateBack的使用
  11. 教你如何注册到受限的MSN.COM、passport.com账号
  12. /etc/fstab详细参数配置
  13. linux 文件大小单位显示
  14. python中一般使用几个空格表示缩进_python中使用空格还是使用 Tab键缩进的建议...
  15. 如何制作路演PPT?
  16. linux展示表空间大小,oracle中看表空间大小等
  17. 机器学习面试题之机器学习基础(一)
  18. 【腾讯WeTest干货分享】高并发性能调试经验分享
  19. .Net内部缓存System.Web.Caching.Cache 和Redis缓存缓存工厂切换
  20. VScode软件入门:用户自定义代码块+常用快捷键+常用扩展插件

热门文章

  1. 非涉密计算机检查的通知,关于开展非涉密计算机及可移动存储介质专项清理活动的紧急通知...
  2. Android之webview长按超链接类型获取链接文字及url、长按图片链接类型分别获取图片和链接的url
  3. Android之解决PC浏览器上传表单文件到手机服务器read数据错误导致有时候下载到手机的文件打开文字错乱问题
  4. Android之解决PC浏览器访问手机服务端取assets目录下的文件页面显示不出来问题
  5. linux c之通过管道父子进程实现同步通信
  6. Android之Animation动画的介绍及用法
  7. 情人节,我表白了CSDN小姐姐后,竟然...【为表白写了一个绘图工具,让我不再手残】
  8. python 实现装饰器设计模式
  9. sql drop 简单操作(Mysql)
  10. 迅捷路由器 服务器无响应,如果路由器重启还是上不了网 几招搞定