📅  最后修改于: 2023-12-03 15:16:37.629000             🧑  作者: Mango
本篇文档介绍如何使用Java编写程序来找到两个数组中最小和的k对。
给定两个大小为 n 和 m 的整数数组 nums1 和 nums2,以及一个整数 k。定义一对值 (u,v),其中第一个元素来自 nums1,第二个元素来自 nums2。找到和最小的 k 对数字 (u1,v1), (u2,v2) ... (uk,vk)。
1. 暴力枚举
我们可以将两个数组的所有元素对进行组合(笛卡尔积),然后按照和的大小排序,从小到大选择前k对即可。
时间复杂度:$O(nm log nm)$
代码如下:
public List<List<Integer>> kSmallestPairs(int[] nums1, int[] nums2, int k) {
List<List<Integer>> res = new ArrayList<>();
if (nums1 == null || nums2 == null || nums1.length == 0 || nums2.length == 0) {
return res;
}
int n = nums1.length, m = nums2.length;
PriorityQueue<int[]> pq = new PriorityQueue<>((o1, o2) -> (o1[0] + o1[1]) - (o2[0] + o2[1]));
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
pq.offer(new int[]{nums1[i], nums2[j]});
}
}
for (int i = 0; i < k && !pq.isEmpty(); i++) {
int[] cur = pq.poll();
res.add(Arrays.asList(cur[0], cur[1]));
}
return res;
}
2. 堆
我们可以创建一个小根堆,将每个数组中的第一个元素以及它在数组中的下标封装为一个对象,并将这些对象插入小根堆。
每次从小根堆中取出和最小的对象,然后将其对应数组中的下一个元素以及它的下标封装为一个新的对象插入小根堆,如此操作k次。
时间复杂度:$O(k log min(n, m))$
代码如下:
public List<List<Integer>> kSmallestPairs(int[] nums1, int[] nums2, int k) {
List<List<Integer>> res = new ArrayList<>();
if (nums1 == null || nums2 == null || nums1.length == 0 || nums2.length == 0) {
return res;
}
int n = nums1.length, m = nums2.length;
PriorityQueue<int[]> pq = new PriorityQueue<>((o1, o2) -> (o1[0] + o1[1]) - (o2[0] + o2[1]));
for (int i = 0; i < n; i++) {
pq.offer(new int[]{nums1[i], nums2[0], 0});
}
while (k-- > 0 && !pq.isEmpty()) {
int[] cur = pq.poll();
res.add(Arrays.asList(cur[0], cur[1]));
if (cur[2] == m - 1) {
continue;
}
pq.offer(new int[]{cur[0], nums2[cur[2] + 1], cur[2] + 1});
}
return res;
}
本文介绍了如何使用Java在两个数组中找到最小和的k对。
暴力枚举的时间复杂度较高,但是实现简单,可以通过。堆的算法实现较为复杂,但是效率更高,可以快速解决大规模数据的问题。
建议面试前先自己实现一遍这两种算法。