如何在一个无序的数组中寻找最大的k个数?
对于这个问题, 最容易想到的办法就是给数组排个序, 如果使用快速排序,时间复杂度是O(nlogn), 但事实上我们只需要寻找这k个数,排序的方法显然做了多余的事情。
那么,能不能在这个基础上优化一下呢?
基于快速排序的优化 O(klogn)
我们知道,快速排序的思想是:在数组中选中一个支点,以这个支点将数组划分成两部分s1, s2,保证s1所有元素小于支点,s2不小于(用“不小于”好像严谨一些)支点。
现在,我们修改一下,让s2中所有元素不小于支点,s2中所有元素小于支点。假设支点所在位置为i,那么:
- 当 i < k 时,我们已经找到了最大k个数中的i个,只需要在右边部分寻找剩下的 k - i 个数;
- 当 i > k 时,那么在前 i - 1 个数当中寻找最大的k个数;
- 当 i == k 时,前 i 个数就是我们要找的最大k个数;
接下来给出代码实现:
1 | function swap(arr, i, j) { |
基于堆排序的优化 O(klogn)
首先需要了解一下堆(二叉堆)的概念:
堆(英语:Heap)是计算机科学中的一种特别的树状数据结构。若是满足以下特性,即可称为堆:“给定堆中任意节点P和C,若P是C的母节点,那么P的值会小于等于(或大于等于)C的值”。若母节点的值恒小于等于子节点的值,此堆称为最小堆(min heap);反之,若母节点的值恒大于等于子节点的值,此堆称为最大堆(max heap)。在堆中最顶端的那一个节点,称作根节点(root node),根节点本身没有母节点(parent node)。
构建一个最大堆:
1 | function heapify(arr, start, end) { |
堆排序:
1 | function heap_sort(arr, len) { |
如果理解了上面的代码,那么寻找最大k个数就很简单了:
1 | function heap_sort(arr, len) { |
以上两种方法都把时间复杂度从O(nlogn)优化了一些,变成了O(klogn)。
(ps:如有描述不当之处欢迎指正)