遇到了一个很简单而有意思的问题,可以看出不同的算法策略对这个问题求解的优化过程。
问题:寻找数组中的第K大的元素。

最简单的想法是直接进行排序,算法复杂度是O(N*logN)。这么做很明显比较低效率,因为不要求别的信息只要计算出第K大的元素。当然,如果在某种情况下需要频繁访问第K大的元素就可以先进行一次排序在直接得出结果。

第一种方式是这样,用选择排序,冒泡法,或者交换排序这类的排序,对前K个元素进行排序。这三种算法也许不是最快的排序算法。但是都有个性质:计算出最大(小)的元素的算法复杂度是O(N)。这个过程不能中断,要计算第三大的元素必须建立在已经算出第二大的元素的基础上(因为每次都是计算当前数组最大)。所以它的算法复杂度是O(N*K);

第二种方法是用快速排序的思想。快速排序每次把一个元素交换到正确的位置,同时把左边的都方上大的,右边都放上小的。这个算法每一次选取一个枢纽元,排序之后,查看枢纽元的位置。如果它的位置大于K,就说明,要求出前面一个子序列的第K大的元素。反之,如果小于K,就说明要求出在后面一个序列的第K - 前一个序列的长度个元素。

如此,就把这个问题改变成了一个可以用快排思想解决的问题。对于快速排序,算法复杂度是O(N*logN)。而这个算法的算法复杂度是O(N)。为什么呢?

其实这个地方的算法复杂度分析很有意思。第一次交换,算法复杂度为O(N),接下来的过程和快速排序不同,快速排序是要继续处理两边的数据,再合并,合并操作的算法复杂度是O(1),于是总的算法复杂度是O(N*logN)(可以这么理解,每次交换用了N,一共logN次)。但是这里在确定枢纽元的相对位置(在K的左边或者右边)之后不用再对剩下的一半进行处理。也就是说第二次插入的算法复杂度不再是O(N)而是O(N/2),这不还是一样吗?其实不一样,因为接下来的过程是1+1/2+1/4+........ < 2,换句话说就是一共是O(2N)的算法复杂度也就是O(N)的算法复杂度。

这个算法目前我在数据结构和算法书上和剑指Offer上都看到过。算是一种很经典很经典的算法。原因是因为他通过努力把算法复杂度在每次递归中下降一些,最终让整个算法的复杂度下降极多,算是一种十分聪明的做法。

第三种方法很是简单,但是使用它需要某个条件,也就是输入数组的取值范围很小,最好的情况是能形成完全分布,也就是1000大小的数组里面的数字是从1到1000这样子。首先,生成一个能够完全装下原数组的数组,这个地方的装下是指数组大小等于原数组最大元素(也许还有优化,但这么描述简单一点),比如原数组是[1,2,3,4,5],我要生成的数组大小是5,如果原数组是[5,3,6,10],我要生成的数组大小是10。接下来遍历原数组,把每一个元素放到第二个数组对应的下标处,5就放在下标为5的地方(实际过程中要减1,因为是数组从0开始)。放的过程中增加元素值用来统计这个元素出现的次数。这一过程算法复杂度是O(N)。接下来,再遍历生成的数组,找出第K大的元素。
这个过程的算法复杂度是多少呢?其实这个和原数组很有关系,原数组越离散也就越糟糕。比如原数组是[1,1000],这样就十分糟糕。第二部的算法复杂度是O(M),M是前数组的最大值。总的算法复杂度O(N)+O(M);

由此可见第三种方法在这个问题的处理非常不好。虽然第三种方法限制颇多(浮点型和负数还有对原数组大小的要求),但是第三种方法的实质是一种散列。就是把原来的映射关系变成了一种反映射。也就是说如果形成了数据与地址的直接映射。但是这种映射的问题也体现的很明显,它这么做也只能算是捡了个漏子,如果输入数组稍微一边,还是一样要用hash算法计算其hash值。再把hash值映射到地址上。

第四种方法是用二叉堆来做。对大小为N的数组构建二叉堆的算法复杂度是O(N)。然后每次下滤的算法复杂度是O(logN),一共下滤K次,算法复杂度是O(N+K*logN)。

这种做法比较适合用来处理输入数组极大的情况,原因是如果输入数组大到不能放入内存,那么构建二叉堆(优先队列)的时候就可以只构造一个K个元素的优先队列。如果下一个元素比这个最小堆的堆顶还小就直接pass。第二个原因是算法二在对付一个极大的输入队列的时候算法复杂度的一个常数会很大。

寻找数组中的第K大的元素,多种解法以及分析的更多相关文章

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

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

  2. 记录我对'我们有成熟的时间复杂度为O(n)的算法得到数组中任意第k大的数'的误解

    这篇博客记录我对剑指offer第2版"面试题39:数组中出现次数超过一半的数字"题解1的一句话的一个小误解,以及汇总一下涉及partition算法的相关题目. 在剑指offer第2 ...

  3. [LeetCode] Kth Largest Element in a Stream 数据流中的第K大的元素

    Design a class to find the kth largest element in a stream. Note that it is the kth largest element ...

  4. LeetCode:数组中的第K个最大元素【215】

    LeetCode:数组中的第K个最大元素[215] 题目描述 在未排序的数组中找到第 k 个最大的元素.请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素. 示例 1: ...

  5. LeetCode215. 数组中的第K个最大元素

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

  6. LeetCode 215——数组中的第 K 个最大元素

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

  7. Leetcode 215.数组中的第k个最大元素

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

  8. Leetcode题目215.数组中的第K个最大元素(中等)

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

  9. 215. 数组中的第K个最大元素 + 快速排序 + 大根堆

    215. 数组中的第K个最大元素 LeetCode-215 另一道类似的第k大元素问题:https://www.cnblogs.com/GarrettWale/p/14386862.html 题目详情 ...

随机推荐

  1. vijos1431[noip2007]守望者的逃离(背包动规)

    描述 恶魔猎手尤迪安野心勃勃,他背叛了暗夜精灵,率领深藏在海底的娜迦族企图叛变.守望者 在与尤迪安的交锋中遭遇了围杀,被困在一个荒芜的大岛上.为了杀死守望者,尤迪安开始对这 个荒岛施咒,这座岛很快就会 ...

  2. poj1416 Shredding Company

    Shredding Company Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 5379   Accepted: 3023 ...

  3. bzoj3223 文艺平衡树 (treap or splay分裂+合并)

    3223: Tyvj 1729 文艺平衡树 Time Limit: 10 Sec  Memory Limit: 128 MB Submit: 3313  Solved: 1883 [Submit][S ...

  4. Padrino 生成器指南

    英文版出处:http://www.padrinorb.com/guides/generators Padrino提供了用于快速创建应用的生成器,其优势在于构建推荐的Padrino应用结构.自动生成罗列 ...

  5. CSS3 perspecitve属性

    M M .div1 { position: relative; height: 150px; width: 150px; margin: 0px; padding:2px; border: 1px s ...

  6. grains

    用途 1,匹配客户端 2,配置文件里使用 3,资产管理     定义grains方法1:             方法2:        

  7. zabbix-proxy3.0.4编译安装

    数据库配置: innodb_file_per_table=1   安装mysql rpm -ivh http://dev.mysql.com/get/mysql-community-release-e ...

  8. TinyFrame开篇:基于CodeFirst的ORM

    前言 做项目的这段时间,由于比较忙,一直没有机会闲下来思考.正好趁目前手头活儿轻松点,就花了一两天时间搭建了一个比较简单的框架,名称暂时就叫做:TinyFrame吧.顾名思义,就是微框架的意思.虽然这 ...

  9. Use Dapper ORM With ASP.NET Core

    Dapper.NET is not just another ORM tool, it's considered as the king of ORM. Because it's fast, easy ...

  10. FineUI小技巧(4)关闭窗体那些事

    前言 FineUI中的Window控件常用作选择.新增或编辑内容.而关闭Window控件却有很多技巧,了解这些技巧有助于项目的快速开发. 如何关闭Window控件 第一个问题就是如何关闭Window控 ...