在单程中找到第K个最大数字而不存储整个数组

时间:2011-06-22 21:30:08

标签: arrays algorithm selection space-complexity

我想到的算法是

  • 保持MaxHeap的大小为K
  • 插入每个元素
  • 如果堆已满,则删除较小的值
  • 最后,Kth max是MaxHeap中较小的

那会给我O(NlogK)。有更好的算法吗?我不能快速选择,因为数组不能存储在内存中。

5 个答案:

答案 0 :(得分:11)

根据您的内存限制,您可以使用中位数中值算法的修改版本来解决O(n)时间和O(k)空间中的问题。

这个想法如下。在内存中维护一个大小为2k的数组。用数组中的前2k个元素填充此缓冲区,然后在其上运行中位数中值算法,将最大的k个元素放在数组的前半部分中,将最小的k个元素放在后半部分中。然后,丢弃最小的k个元素。现在,将下一个k元素加载到数组的后半部分,使用中位数中值算法再次将前k个元素放在左侧,将底部k个元素放在右侧。如果你在整个数组中迭代这个过程 - 用数组中的下一个k元素替换缓冲区的后半部分,然后使用中位数中位数将那些中位数的k移动到左半部分 - 然后在最后你将在数组的左半部分有前k个元素。找到最小的那些(在O(k)时间内)将给你第k个最大的元素。

总的来说,您最终使用大小为O(k)的数组对中位数算法进行O(n / k)调用,这是对采用O的算法的O(n / k)调用( k)时间,对于O(n)的净运行时间。这与最后一步相结合,在O(n + k)= O(n)时间内运行。此外,由于中位数中位数的内存使用量为O(k),并且由于您有一个大小为O(k)的缓冲区,因此仅使用O(k)内存。换句话说,它比min-heap解决方案渐近地快,并且在内存中渐近等效。<​​/ p>

希望这有帮助!

答案 1 :(得分:1)

这称为http://en.wikipedia.org/wiki/Selection_algorithm

一种算法尤其是http://en.wikipedia.org/wiki/Selection_algorithm#Linear_general_selection_algorithm_-_Median_of_Medians_algorithm

O(N)时间和O(1)空间。我相信如果您的数组没有排序,它可以就地完成。如果您的阵列存储在外部(硬盘,网络等),您可以利用您必须使用的~K字词。如果您的数组是由函数动态生成的,那么您将处于类似情况。

答案 2 :(得分:0)

略微修改算法,因为maxheap不支持高效的“查找最小”。

  • 将前K个项目插入a 最小堆
  • 对于其余项目,如果该值大于堆 头

    • 弹出头部,然后插入新项目。
  • 头部是第K个最大的项目。

对于输入,最坏的情况仍然是O(N lg K),其中每个项目都大于最后一个K的最小值。但对于随机分布的输入,您只需要在较小的输入上执行堆操作物品的百分比。

答案 3 :(得分:0)

运行此代码 - 运行正常,无需触摸元素位置或对其进行排序。

public class nth {

    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        calc.getit(2);
    }

}
class calc{
    static int arr[] = { 1, 23, 47, 81, 92, 87, 52, 48, 56, 66, 65, 76, 71, 85,
        49, 53, 56, 61, 65, 84 };

    static void getit(int k){
        int i,j=0;
        for(i=0;i<arr.length;i++){
            int c=0;
            for(j=0;j<arr.length;j++){
                if(arr[i]>arr[j]){
                    c++;
                }
            }
            if(c==k-1){
                System.out.println(arr[i]);
            }
        }
    }
}

答案 4 :(得分:0)

我有一个使用PriorityQueue的实现。试试这个:

import java.util.PriorityQueue;

public class FindKthLargestElementWithHeap {

    /**
     * We can use a min heap to solve this problem. 
     * The heap stores the top k elements.
     * Whenever the size is greater than k, delete the min.
     * Time complexity is O(nlog(k)).
     * Space complexity is O(k) for storing the top k numbers.
     */
    public static int findKthLargest(int[] nums, int k) {
        PriorityQueue<Integer> q = new PriorityQueue<>(k);
        for(int i: nums){
            q.offer(i);

            if(q.size()>k){
                q.poll();
            }
        }

        return q.peek();
    }

    public static void main(String args[]) {
        int[] nums = {5,8,6,97,12,3,5,6,4,2,3,};
        //Return the second largest number
        System.out.println(findKthLargest(nums,2));
    }

}

有关详细信息,请访问:https://github.com/m-vahidalizadeh/foundations/blob/master/src/data_structures/FindKthLargestElementWithHeap.java