我正在寻找从输入数组返回顶级k
元素的有效方法
一种方法是对数组进行排序并从数组末尾返回k
元素。
还有其他方法建议使用here,其中一种方法使用 quickselect算法,但根据我的理解,quickselect仅返回未排序数组中的k
- th元素。返回后,k
左侧和右侧的元素仍然未排序。
所以它应该是这样的:
while k>0{
quickselect(int[] arr, k);
k--;
}
快速选择为O(n)
,我们会k
次进行,因此整体时间复杂度为O(n*k)
。
但是帖子中的数据表明这比O(n log n)
更好
从一百万个样本中选择前200个在前一个案例中意味着200 million
,而在后一个案例中意味着20 million
。显然,这要好得多。
我的理解是如何使用quickselect来选择正确的前200个元素?
答案 0 :(得分:3)
不,您不需要O(nk)
时间 - 可以在O(n)
(平均情况)中完成。
快速选择的最终结果是从数组末端开始的第k个位置的第k个元素,左边是较小的元素,右边是较大的元素。
因此,从该元素到右边的所有元素都将是k个最大的元素 - 在O(k)
中提取这些元素(使用简单的for循环)将是微不足道的,这将最终导致总运行时间O(n)
。
或者,因为在运行quickselect之后你已经知道了第k个元素,你可以再次遍历数组并提取大于或等于该元素的所有元素(这可以在一次传递中完成 - 也是{{ 1}})。
如果您想按排序顺序返回它们,则需要额外的O(n)
(对它们进行排序)。
答案 1 :(得分:2)
如果n不是太大但是如果你有非常大的n(太大而不适合内存)或未知的n(如果你看到无限的样本流并且你希望能够报告200),则快速选择是好的到目前为止看到的最大值)然后另一种方法是保持k元素最小堆,每次看到一个新元素时,将它与最小堆的顶部进行比较(迄今为止200个最大元素中最小的一个)如果它更大,则弹出堆的旧顶部并将新元素推送到堆上。