【一起来刷题java】——TOPK问题

topk问题——建大小为K的堆

[参考文献]((382条消息) 拜托,面试别再问我TopK了!!!_架构师之路-CSDN博客)

本文参考了上面的文章,并做了自我总结,希望会有所帮助。

topK问题:从很多个数中得到较大的K个元素。

我们固然可以建成一个大堆,然后弹出K次就可以找到前K个元素,但是建立一个N个元素的大根堆,再每次向下调整的时间复杂度是O(n*lgn)

所以,为了简化这个问题,就可以让N个数的前k个元素建立一个只有k个元素的小根堆,小根堆的堆顶就是最小的元素,

image-20220128222900614

对于n-k个元素,如果哪个元素比堆顶的元素大,那么就pop堆顶元素,然后将该元素加入堆中

image-20220128222918058

这样,遍历完成该操作后,留下来的就是前K个大的元素

image-20220128222943561

这样的时间复杂度就是O(n*lgk)比上面的快了很多

其他结论:

  • 堆顶的元素就是第K大的元素
  • 其他的非堆顶的元素就是先K个大的元素

代码实现:

class Solution {
    public int[] topK(int[] nums, int k) {
        PriorityQueue<Integer> pq=new PriorityQueue<>();
        for(int i=0;i<nums.length;i++){
            if(i<k){
                pq.offer(nums[i]);
            }else{
                if(nums[i]>pq.peek()){
                    pq.poll();
                    pq.offer(nums[i]);
                }
            }
        }
        int[] ret=new int[k];
        for(int i=0;i<k;i++){
            ret[i]=nums[i];
        }
        return ret;
    }
}

查找和最小的K对数字

[题目链接](373. 查找和最小的 K 对数字 - 力扣(LeetCode) (leetcode-cn.com))

上面的这道题和topK问题是差不多的,只是多了数对的问题。

使用了list而已

class Solution {
    public List<List<Integer>> kSmallestPairs(int[] nums1, int[] nums2, int k) {
        PriorityQueue<List<Integer>> priorQueue = new PriorityQueue<>(k, new Comparator<List<Integer>>() {
            @Override
            public int compare(List<Integer> o1, List<Integer> o2) {
                return (o2.get(0)+o2.get(1))-(o1.get(0)+o1.get(1));
            }
        });
        //注意要取K,和length的最小值,因为这个是一个升序数组,防止因length太大而陷入死循环
        for(int i=0;i<Math.min(nums1.length,k);i++){
            for(int j=0;j<Math.min(nums2.length,k);j++){
                if(priorQueue.size()<k){
                    List<Integer> list=new ArrayList<>();
                    list.add(nums1[i]);
                    list.add(nums2[j]);
                    priorQueue.offer(list);
                }else{
                    int top=priorQueue.peek().get(0)+priorQueue.peek().get(1);
                    if(nums1[i]+nums2[j]<top){
                        priorQueue.poll();
                        List<Integer> list=new ArrayList<>();
                        list.add(nums1[i]);
                        list.add(nums2[j]);
                        priorQueue.offer(list);
                    }
                }

            }
        }
        List<List<Integer>> retlist=new ArrayList<>();
        int size=priorQueue.size();
        for(int i=0;i<size;i++){
            retlist.add(priorQueue.poll());
        }
       // Collections.reverse(retlist);
        return retlist;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值