给定两个以升序排列的整数数组 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
这个问题可以使用双指针的方法来解决。我们可以遍历两个数组,对于每一个元素,都找到它在另一个数组中的第一个大于它的元素,并更新最小和。然后,将当前的数对添加到结果列表中,并将较小的数组的指针向前移动一位。
具体来说,我们可以按照以下步骤来进行:
1. 初始化一个空的结果列表 res 和一个整数变量 k。
2. 使用两个指针 i 和 j 分别指向 nums1 和 nums2 的头部。
3. 遍历数组,对于每一个元素,都找到它在另一个数组中的第一个大于它的元素,并更新最小和。如果找不到这样的元素,则返回 null。
4. 将当前的数对添加到结果列表中,并将较小的数组的指针向前移动一位。
5. 当结果列表的大小达到 k 时,或者两个数组都被遍历完时,就返回结果列表。
以下是具体的代码实现:
```java
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 = Math.min(nums1.length, nums2.length);
for (int i = 0; i < n && k > 0; i++) {
int minSum = Integer.MAX_VALUE;
int minJ = -1;
for (int j = 0; j < nums2.length; j++) {
int sum = nums1[i] + nums2[j];
if (sum < minSum) {
minSum = sum;
minJ = j;
}
}
if (minJ == -1) {
break;
}
res.add(Arrays.asList(nums1[i], nums2[minJ]));
k--;
if (nums1.length <= nums2.length) {
nums1[i] = nums1[nums1.length - 1];
nums1 = Arrays.copyOf(nums1, nums1.length - 1);
} else {
nums2[minJ] = nums2[nums2.length - 1];
nums2 = Arrays.copyOf(nums2, nums2.length - 1);
}
}
return res;
}
```
这个算法的时间复杂度是 O(n log n),空间复杂度是 O(k)。