返回输入数组中的前K个元素

时间:2014-02-20 00:12:11

标签: arrays algorithm sorting quickselect

我正在寻找从输入数组返回顶级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个元素?

2 个答案:

答案 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个最大元素中最小的一个)如果它更大,则弹出堆的旧顶部并将新元素推送到堆上。