📜  在两个数组中找到和最小的 k 对(1)

📅  最后修改于: 2023-12-03 15:37:39.701000             🧑  作者: Mango

在两个数组中找到和最小的 k 对
问题描述

给定两个长度为 $m$ 和 $n$ 的数组 nums1 和 nums2,以及一个整数 k。

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

找到和最小的 k 对数字 $(u_1,v_1), (u_2,v_2) ... (u_k,v_k)$。

解题思路

这道题的思路非常简单,我们把所有可能的数对都求出来,然后排序,最后取前 k 小的就可以了。

具体来说,我们可以用一个小根堆存储当前所有可能的数对,从桶底开始逐个加入,每次加入一个数对后,将它与它旁边和它上面的数对比较,如果更小就交换位置,直到放到合适的位置。

完成上述操作后,我们就可以在小根堆的前 k 个数里找到和最小的 k 对数字了。

代码演示

Python代码

class Solution:
    def kSmallestPairs(self, nums1: List[int], nums2: List[int], k: int) -> List[List[int]]:
        pairs = []
        for i in nums1:
            for j in nums2:
                pairs.append([i, j])

        def get_sum(pair):
            return pair[0] + pair[1]

        heap = []
        for pair in pairs:
            heapq.heappush(heap, (get_sum(pair), pair))

        res = []
        for i in range(min(k, len(heap))):
            res.append(heapq.heappop(heap)[1])

        return res

Java代码

class Solution {
    public List<List<Integer>> kSmallestPairs(int[] nums1, int[] nums2, int k) {
        List<List<Integer>> res = new ArrayList<>();
        PriorityQueue<int[]> heap = new PriorityQueue<>((a, b) -> a[0] + a[1] - b[0] - b[1]);

        for (int i : nums1) {
            for (int j : nums2) {
                heap.offer(new int[]{i, j});
            }
        }

        for (int i = 0; i < k && !heap.isEmpty(); i++) {
            int[] pair = heap.poll();
            res.add(Arrays.asList(pair[0], pair[1]));
        }

        return res;
    }
}
时间复杂度分析

假设 nums1 的长度为 m,nums2 的长度为 n,那么我们一共会找出 mn 对数字,所以时间复杂度为 O(mn log(mn)),其中 log(mn) 是由于我们要在小根堆中维护元素,这涉及到了对数级别的时间复杂度。如果 k 很小,不超过 mn,那么实际的时间复杂度就为 O(k log(k))。