zoukankan      html  css  js  c++  java
  • 算法题004 寻找最大的K个数

    寻找最大的K个数

     

    题目描述

      有很多个无序的数,怎么选出其中最大的若干个数?

      即,从n个数中选出最大的K个数。

     

    解法一

      先假设元素的数量不大,例如在几千个左右,在这种情况下,我们就排序吧。

      在这里,快速排序或堆排序都是不错的选择,他们的平均时间复杂度都是O(nlog2n),然后取出钱K个,O(K)。

      总的时间复杂度仍然是O(nlog2n)

      可以注意到,即便是K=1的情况,上面的算法复杂度仍然是O(nlog2n),而显然,我们可以通过n-1此的比较和交换得到结果,不需要对整个数组进行排序。

      要避免做后面n-K个数的排序,可以使用部分排序算法,选择排序和冒泡排序都是不错的选择。

      把n个数中的前K个数排序出来,复杂度是O(n*K)

      哪一个更好呢?O(nlog2n) 和O(n*K)这取决于K的大小,在K<log2n的情况下,可以选择部分排序。

     

    解法二

      回忆一下快速排序,快排中的每一步,都是将数据分为两组,其中一组的任何数都小于另一组中的任何数,不断地对数据进行分割直到不能再分即完成排序。

      假设n个数存储在数组S中,从S中找出一个元素X,它把数组分为比它大的和比它小的两部分,假设比它大的一部分数组是Smax,比它小的部分是Smin。

      这时有两种可能:

      1.Smax中元素不足K个,说明Smax中的所有数和Smin中最大的K-|Smax|个元素就是数组S中最大的K个数;

      2.Smax中元素的个数大于或等于K,则需要返回Smax中最大的K个元素。

      这样递归下去,问题的规模不断地变小,平均时间复杂度O(n * log2K)

     

    解法三

      寻找n个数中最大的K个数,本质上就是寻找这K个数中最小的那个,也就是第K大的数。

      可以使用二分搜索的策略。对于一个给定的数p,可以在O(n)的时间复杂度内找出所有不小于p的数。

      (此方法详述部分略)。

     

    解法四:如果N非常非常大呢?

      前面三个解法都需要对数据访问多次,如果n很大呢?100亿?这个时候数据不能全部装入内存,所以要求尽可能少地遍历所有数据。

      前K个数中最大的K个数是一个退化的情况,所有K个数就是最大的K个数,如果考虑第K+1个数,则它和前面K个数的最小值进行比较,比其大则替换它。

      如果用一个数组来存储最大的K个数,每加入一个数X,就扫描一遍数组,得到数组中最小的数Y。X和Y进行比较,替换它或者保持原数组不变。这种方法,所耗费的时间复杂度为O(n * K)

      进一步,可以用容量为K的最小堆来存储最大的K个数。最小堆的堆顶元素就是最大K个数中最小的一个。每次新考虑一个数X,如果X小于堆顶则舍弃,如果X大于堆顶,那么用X替换堆顶,然后更新堆来维持堆的性质。(因为X可能并不是最小值,所以堆结构需要更新)。更新过程花费的时间复杂度为O(log2K)。

      因此,算法的时间复杂度为O(n * log2K),这实际上是部分执行了堆排序的算法。

     

    解法五

      如果所有n个数都是整数,且它们的取值范围不太大,可以考虑申请空间,记录每个整数出现的次数,然后再从大到小取最大的K个。

      比如用数组count,count[i]表示整数i出现的次数。

      极端情况下,如果n个整数各不相同,只需要一个bit来存储这个整数是否存在。

      实际情况下,并不一定能保证所有元素都是正整数,且取值范围不太大。但是这种方法仍然可以推广适用。比如把取值区间分成多块,然后统计各个小区间中元素的个数。可以知道第K大的元素在哪一个小区间,然后再对那个小区间继续进行分块处理。

     

    参考资料

      《编程之美》2.5节。

      本题目其他相关链接:

      链接1:http://blog.csdn.net/koala002/article/details/6415485

      链接2:http://www.cnblogs.com/luxiaoxun/archive/2012/08/06/2624799.html

      本博客关于排序算法的回顾:

      排序算法:http://www.cnblogs.com/mengdd/archive/2012/11/24/2786346.html

     

     

  • 相关阅读:
    list容器的sort函数
    c++ vector迭代器删除元素
    vs中属性页常用配置介绍2
    vs中属性页常用配置介绍
    error 不是类或命名空间
    实习代码编写中,一些有用的经验
    vs2015环境下生动动态链接库及使用
    STL容器使用的时机
    c++文件和流
    c++接口(抽象类,虚函数,纯虚函数)
  • 原文地址:https://www.cnblogs.com/mengdd/p/2954914.html
Copyright © 2011-2022 走看看