leetcode
leetcode 2951 ~ 3000
查找和最小的 K 对数字

查找和最小的 K 对数字

难度:

标签:

题目描述

English description is not available for the problem. Please switch to Chinese.

代码结果

运行时间: 32 ms, 内存: 16.5 MB


/*
 * 思路:
 * 1. 使用嵌套的流生成所有可能的数对,并按和排序。
 * 2. 取出前 k 个数对。
 */
import java.util.*;
import java.util.stream.*;

public class Solution {
    public List<int[]> kSmallestPairs(int[] nums1, int[] nums2, int k) {
        return Arrays.stream(nums1)
            .boxed()
            .flatMap(u -> Arrays.stream(nums2).mapToObj(v -> new int[]{u, v}))
            .sorted(Comparator.comparingInt(a -> a[0] + a[1]))
            .limit(k)
            .collect(Collectors.toList());
    }
}

解释

方法:

本题解采用了最小堆(优先队列)的方法来解决问题。首先,将 nums1 中的前 k 个元素与 nums2 中的第一个元素组成的数对,以及它们的和作为优先级,加入最小堆中。然后,每次从堆中取出和最小的数对,将其加入答案列表中。同时,如果该数对的 nums2 元素不是 nums2 的最后一个元素,则将该数对的 nums1 元素与 nums2 中下一个元素组成的新数对加入堆中。重复这个过程,直到找到 k 对数或堆为空。

时间复杂度:

O(k log k)

空间复杂度:

O(k)

代码细节讲解

🦆
在选择初始化堆时,为什么只考虑了nums1中的元素与nums2中第一个元素组成的数对,而没有考虑nums2的元素与nums1中元素的组合?
这种策略是为了避免在堆初始化阶段就将所有可能的数对组合加入堆中,从而导致空间复杂度和时间复杂度过高。初始化时只考虑nums1的元素与nums2第一个元素的组合,是因为这样可以保证堆中始终维持最小的数对和,每次从堆中取出的都是当前已知的和最小的数对。之后每取出一个数对,再逐步考虑该数对的nums1元素与nums2中的下一个元素的组合,这样既控制了堆的大小,也能保证逐步找到k个最小和的数对。如果从一开始就考虑所有组合,堆的大小将难以控制,且初始化和处理的时间复杂度都会显著增加。
🦆
在处理过程中,当从堆中取出一个数对后,为何只考虑该数对的nums1元素与nums2中的下一个元素组成新的数对,并没有考虑nums1中的下一个元素?
当从堆中取出一个数对后,考虑该数对的nums1元素与nums2中的下一个元素组成新的数对,是为了保证逐步扩展搜索空间,并且避免重复添加相同的数对。如果同时考虑nums1中的下一个元素,会导致重复和不必要的计算,因为对于每个nums1中的元素,它与nums2中每个元素的组合在初始化堆的时候已经按需逐步被加入了。这种方法确保了每次扩展都是基于当前已知的最小数对和,且每次扩展都有序且不重复,从而有效控制了堆的大小和算法的执行效率。
🦆
如果nums1或nums2为空数组,这个算法应该如何处理来避免错误或无效的操作?
如果nums1或nums2是空数组,则没有有效的数对可以形成。在这种情况下,算法在开始执行前应该先检查nums1和nums2的长度。如果其中任何一个数组为空,直接返回一个空列表作为结果。这种预先检查可以避免进一步的无效操作,并且保证算法的鲁棒性。例如,在算法的开始添加如下代码:`if not nums1 or not nums2: return []`,这样可以在数据不满足条件时,及时返回结果,避免后续的无效计算。

相关问题