对顶堆,求第K大的数

对顶堆,顾名思义就是两个相对的堆。O(logn)

0即上方是一个维护最小值的小根堆smheap,下方则维护最大值的大根堆bgheap

利用这样的性质,我们就可以求中位数、动态维护K大值。优先队列是用堆来实现的。

思路:(我们必须保证小根堆里面的所有值是大于大根堆里面所有值的)

1. 如果要插入的值x>smheap.top(),那么就往smheap里面放。

2. 如果要插入的值x<=smheap.top(),那么就往bgheap里面放。

3. 如果smheap.size() == bgheap.size() + 2,那么就把smheap的堆顶元素移入bgheap

4. 如果bgheap.size() == smheap.size() + 2,那么就把bgheap的堆顶元素移入smheap

PriorityQueue<Integer> pq = new PriorityQueue<>(); //小根堆
PriorityQueue<Integer> pq1 = new PriorityQueue<>(new Comparator<Integer>() {
    @Override
    public int compare(Integer o1, Integer o2) {
        if (o1 == o2) {
            return 0;
        } else {
            if (o1 > o2) {
                return -1;
            } else {
                return 1;
            }
        }
    }
});//大根堆

public double findMedianSortedArrays(int[] nums1, int[] nums2) {
    for (int i = 0; i < nums1.length; i++) {
        insert(nums1[i]);
    }
    for (int i = 0; i < nums2.length; i++) {
        insert(nums2[i]);
    }
    if(pq.size() == pq1.size() + 1) return pq.peek();
    else if(pq1.size() == pq.size() + 1) return pq1.peek();
    return (pq.peek() + pq1.peek()) / 2.0;
}

private void insert(int x) {
    if (pq.isEmpty() || x > pq.peek()) {
        pq.add(x);
    } else {
        pq1.add(x);
    }
    if(pq.size() == pq1.size() + 2){
        pq1.add(pq.poll());
    } else if(pq1.size() == pq.size() + 2){
        pq.add(pq1.poll());
    }
}

第K大数

一、 nth_element(first,nth,last) stl中的一个函数 时间复杂度是O(n)

主要实现:利用快排的思想,在[L,R]上,通过线性的扫描交换,使[L,mid)的元素都比mid小,(mid,R]的元素都比mid大,此时mid上的元素就是第mid小的元素,然后判断k在mid的哪边,在进行递归处理。
实际上也就是每次只处理一半的范围。

二、维护一个k大小的最小堆,这种方法可以用于数据量存放不下,极大减小了空间复杂度。

三、利用hash保存数组中元素Si出现的次数,利用计数排序的思想,线性从大到小扫描过程中,前面有k-1个数则为第k大数,平均情况下时间复杂度O(n)

海量数据(Top k)

 

 

点赞