剑指offer61:和最小的k个数对

本文介绍了一种优化算法,用于解决给定两个升序数组寻找和最小的k对数对的问题。通过使用最大堆,仅考虑每个数组的前k个元素,降低了时间复杂度至O(k^2 log k)。详细讲解了算法原理和代码实现,适合对数据结构和算法优化感兴趣的读者。
摘要由CSDN通过智能技术生成

题目:
给定两个以升序排列的整数数组 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]
分析:
要求找出和最小的k个数对,可以用最大堆来存储这k个和最小的数对,逐一将m*n个数对添加到最大堆中。当堆中的数对的数目小于k时,直接将数对添加到堆中,如果堆中已经由k个数对,那么先要比较待添加的数对之和大于或等于堆顶的数对之和,如果待添加的数对之和小于堆顶的数对小于堆顶的数对之和,那么删除堆顶的数对,并将待添加的数对添加到堆中,这样可以确保堆中存储的是和最小的k个数对。具体思路和59题思路类似,考虑如何优化一下,题目中给出的条件以升序排列还没有利用到,不管输出的数组nums1有多长,最多只考虑前k个数字,同理,不管输入的数组nums2有多长,最多只考虑前k个数字,比如如果第一个数组中第k+1个数字和第二个数组中某个数字组成的数对p,该数对之和一定不是最小的k个数对中的一个,因为第一个数组中前k个数字和第二个数组中同一个数字组成的k个数对之和都要小于数对p之和。所以无论两个数组多长,都只考虑各自的前k个数字。时间复杂度为O(k ^2logk).
代码:

import java.lang.reflect.Array;
import java.util.*;

public class KSmallestPairs {
//大根堆法
    public List<List<Integer>> kSmallestPairs1(int[] nums1, int[] nums2, int k) {
    //创建大根堆,用一个lambda表达式规定,它的参数是两个数对p1,p2,由于需要一个最大堆,和默认的最小堆比较规则相反,因此返回值是数对p2
    //的和减去p1的和
        Queue<int[]> maxHeap = new PriorityQueue<>((p1,p2) -> p2[0]+p2[1]-p1[0]-p1[1]);
        //不管输出的数组nums1有多长,最多只考虑前k个数字,同理,不管输入的数组nums2有多长,最多只考虑前k个数字
        for (int i = 0; i < Math.min(k, nums1.length); i++) {
            for (int j = 0; j < Math.min(k, nums2.length); j++) {
                if (maxHeap.size() >= k) {
                    int[] root = maxHeap.peek();
                    if (root[0] + root[1] > nums1[i] + nums2[j]) {
                        maxHeap.poll();
                        maxHeap.offer(new int[]{nums1[i], nums2[j]});
                    }
                }else {
                    maxHeap.offer(new int[]{nums1[i], nums2[j]});
                }
            }
        }
        List<List<Integer>> result = new LinkedList<>();
        while (!maxHeap.isEmpty()) {
            int[] vals = maxHeap.poll();
            result.add(Arrays.asList(vals[0], vals[1]));
        }
        return result;
    }
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

龙崎流河

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值