剑指 Offer II 061. 和最小的 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]
提示:
1 <= nums1.length, nums2.length <= 104
-109 <= nums1[i], nums2[i] <= 109
nums1, nums2 均为升序排列
1 <= k <= 1000
分析
方法一:最大堆
时间复杂度O(k2logk)。
利用最大堆,最大堆储存int[]类型,按照数组中两个数的和从大到小排列。
遍历两个数组将前k个最小数对存到最大堆中,最后遍历最大堆存储到list里。
方法二:最小堆
时间复杂度O(klogk)。
利用最小堆,每次获得最小值。最小堆存储int[]类型,数组的第一个数是nums1数组的索引,第二个数是nums2数组的索引,按照两个索引对应数字之和排序。
首先固定nums2的索引0,遍历nums1小于等于k的索引,存储到最小堆中,然后遍历nums2的索引,同时保存最小堆堆顶的索引对应的值到答案中。存够k个或者遍历完数组最后输出即可。
题解(Java)
方法一:
class Solution {
public List<List<Integer>> kSmallestPairs(int[] nums1, int[] nums2, int k) {
Queue<int[]> maxHeap = new PriorityQueue<>((i1, i2) -> i2[0] + i2[1] - i1[0] - i1[1]);
for (int i = 0; i < Math.min(nums1.length, k); i++) {
for (int j = 0; j < Math.min(nums2.length, k); j++) {
if (maxHeap.size() >= k) {
int[] record = maxHeap.peek();
if (record[0] + record[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>> ans = new ArrayList<>();
while (!maxHeap.isEmpty()) {
int[] vals = maxHeap.poll();
ans.add(Arrays.asList(vals[0], vals[1]));
}
return ans;
}
}
方法二:
class Solution {
public List<List<Integer>> kSmallestPairs(int[] nums1, int[] nums2, int k) {
Queue<int[]> minHeap = new PriorityQueue<>((i1, i2) -> nums1[i1[0]] + nums2[i1[1]] - nums1[i2[0]] - nums2[i2[1]]);
for (int i = 0; i < Math.min(nums1.length, k); i++) {
minHeap.offer(new int[] {i, 0});
}
List<List<Integer>> ans = new ArrayList<>();
while (k-- > 0 && !minHeap.isEmpty()) {
int[] record = minHeap.poll();
ans.add(Arrays.asList(nums1[record[0]], nums2[record[1]]));
if (record[1] < nums2.length - 1) minHeap.offer(new int[] {record[0], ++record[1]});
}
return ans;
}
}