如何以最快的方式按顺序查找数组中的前k个最大元素(即从第一个最大元素开始到第k个最大元素)?
以下是一种方案:
使用线性时间的选择算法,如中位数或内省排序,找到第k大的元素,并重新排列元素,使得从第k个元素向后的所有元素都大于第k个元素。
使用快速排序算法(如堆排序或快速排序)对第k个元素向后的所有元素进行排序。
步骤(1)的时间复杂度为O(n),步骤(2)的时间复杂度为O(k log k)。总体而言,该算法的时间复杂度为O(n + k log k),非常非常快。
希望这能帮到您!
1)在O(n)时间内构建一个最大堆树
2)使用“提取最大值”k次,从最大堆中获取k个最大元素,时间复杂度为O(klogn)
时间复杂度:O(n + klogn)
下面是使用STL的C++实现:
#include <iostream>
#include<bits/stdc++.h>
using namespace std;
int main() {
int arr[] = {4,3,7,12,23,1,8,5,9,2};
//Lets extract 3 maximum elements
int k = 3;
//First convert the array to a vector to use STL
vector<int> vec;
for(int i=0;i<10;i++){
vec.push_back(arr[i]);
}
//Build heap in O(n)
make_heap(vec.begin(), vec.end());
//Extract max k times
for(int i=0;i<k;i++){
cout<<vec.front()<<" ";
pop_heap(vec.begin(),vec.end());
vec.pop_back();
}
return 0;
}
基数排序解决方案:
时间复杂度:O(N*L),其中L = 最大元素的长度,可以假设L = O(1)。 空间使用:基数排序需要O(N)的空间。
然而,我认为基数排序有昂贵的开销,使得其线性时间复杂度不太具有吸引力。
O(N + k lg k)
的解决方案。int[] kLargest_Dremio(int[] A, int k) {
int[] result = new int[k];
shouldGetIndex = true;
int q = AreIndicesValid(0, A.Length - 1) ? RandomizedSelet(0, A.Length-1,
A.Length-k+1) : -1;
Array.Copy(A, q, result, 0, k);
Array.Sort(result, (a, b) => { return a>b; });
return result;
}
AreIndicesValid
和 RandomizedSelect
在这个 GitHub 源代码文件中被定义。
有一个关于性能和受限资源的问题。
为前三个值创建一个值类。在并行流中使用这样的累加器进行规约。根据上下文(内存、功率)限制并行性。
class BronzeSilverGold {
int[] values = new int[] {Integer.MIN_VALUE, Integer.MIN_VALUE, Integer.MIN_VALUE};
// For reduction
void add(int x) {
...
}
// For combining two results of two threads.
void merge(BronzeSilverGold other) {
...
}
}
在您的程序中必须限制并行性,因此请在以下位置指定N_THREADS:
try {
ForkJoinPool threadPool = new ForkJoinPool(N_THREADS);
threadPool.submit(() -> {
BronzeSilverGold result = IntStream.of(...).parallel().collect(
BronzeSilverGold::new,
(bsg, n) -> BronzeSilverGold::add,
(bsg1, bsg2) -> bsg1.merge(bsg2));
...
});
} catch (InterruptedException | ExecutionException e) {
prrtl();
}
@templatetypedef的解决方案可能是最快的,假设您可以修改或复制输入。
另外,您可以使用堆或BST(在C++中使用set
)来存储给定时刻的k个最大元素,然后逐个读取数组的元素。虽然这是O(n lg k),但它不会修改输入,并且仅使用O(k)的额外内存。它还适用于流(当您不知道从一开始就有所有数据时)。