TOPK问题:查找和最小的K对数字

给定两个以升序排列的整数数组 nums1 和 nums2 , 以及一个整数 k 。

定义一对值 (u,v),其中第一个元素来自 nums1,第二个元素来自 nums2 。

请找到和最小的 k 个数对 (u1,v1),  (u2,v2)  ...  (uk,vk) 。

示例 1:

输入: nums1 = [1,7,11], nums2 = [2,4,6], k = 3
输出: [1,2],[1,4],[1,6]
解释: 返回序列中的前 3 对数:
     [1,2],[1,4],[1,6],[7,2],[7,4],[11,2],[7,6],[11,4],[11,6]
示例 2:

输入: nums1 = [1,1,2], nums2 = [1,2,3], k = 2
输出: [1,1],[1,1]
解释: 返回序列中的前 2 对数:
     [1,1],[1,1],[1,2],[2,1],[1,2],[2,2],[1,3],[1,3],[2,3]
示例 3:

输入: nums1 = [1,2], nums2 = [3], k = 3 
输出: [1,3],[2,3]
解释: 也可能序列中所有的数对都被返回:[1,3],[2,3]

结题思路:题目要求返回一个List<List<Integer>>数据类型 结果,首先我们得new一个List<List<Integer>>这样的数据类型,然后建立一个大小为k大堆,为什么建立大堆呢?因为大堆在进行筛选的时候可以通过top的值来判定新值是否能入堆,只要是比top值小的组合,就能进入堆,进入堆的数据就是我们需要的数据。那怎么来比较一组数据的大小呢?

思路先把所有对应的List一次放入一个大堆中,当堆的大小小于k,直接放入堆中, 当放满了之后,接着放入元素的时候要判断堆顶元素和放入元的大小,要是放入的元素比堆顶元素小的话,就直接把堆顶元素 抛出,最后把该元素插入到堆中。

PriorityQueue<List<Integer>> priorityQueue = 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的大堆,为什么是大堆呢,因为重写了compare方法,方法返回值是List<Integer>中下标为0和1的值之差,o1代表堆顶元素,o2代表新增元素。

整体代码及解题思路详解

public static List<List<Integer>> kSmallestPairs(int[] nums1, int[] nums2, int k) {
        //思路:先把所有对应的List一次放入一个大堆中,当堆的大小小于k,直接放入堆中,
        //当放满了之后,接着放入元素的时候要判断堆顶元素和放入元的大小,要是放入的元素比堆顶元素小的话,就直接把堆顶元素
        //抛出,最后把该元素插入到堆中
        List<List<Integer>> lists = new ArrayList<>();
        PriorityQueue<List<Integer>> priorityQueue = 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)));
            }
        });
        //遍历num1的数组元素
        for (int i = 0; i < nums1.length; i++) {
            //遍历num2的数组元素
            for (int j = 0; j < nums2.length; j++) {
                //当堆未放满的时候,直接往堆里面插入数据类型为List<Integer>的数据
                if (priorityQueue.size() < k) {
                    //构造List<Integer>类型的数据
                    List<Integer> list = new ArrayList<>();
                    //将num1[i]和num2[j]加入list中
                    list.add(nums1[i]);
                    list.add(nums2[j]);
                    //最后将list加入堆中
                    priorityQueue.offer(list);
                } else {
                    //当堆已经放满了时,这时候需要拿出堆顶元素与新的元素的值进行比较
                    //拿出堆顶元素
                    List<Integer> top = priorityQueue.peek();
                    //堆顶元素的值
                    int topVal = top.get(0) + top.get(1);
                    //当堆顶的值大于新的值,就要把堆顶的元素poll出去,然后把新的元素offer进来
                    if (topVal > nums1[i] + nums2[j]) {
                        //达成条件,poll堆顶元素的值
                        priorityQueue.poll();
                        List<Integer> list = new ArrayList<>();
                        list.add(nums1[i]);
                        list.add(nums2[j]);
                        //把新的值入堆
                        priorityQueue.offer(list);
                    }
                }
            }
        }
        //打印堆中的元素,判断条件有:打印次数首先要小于或等于k,且堆不为空才能输出
        for (int i = 0; i < k && !priorityQueue.isEmpty(); i++) {
            System.out.println(priorityQueue.peek());
            lists.add(priorityQueue.poll());
        }
        //返回堆
        return lists;
    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值