You are given two integer arrays nums1 and nums2 sorted in ascending order and an integer k.
Define a pair (u,v) which consists of one element from the first array and one element from the second array.
Find the k pairs (u1,v1),(u2,v2) ...(uk,vk) with the smallest sums.
Example 1:
Input: nums1 = [1,7,11], nums2 = [2,4,6], k = 3 Output: [[1,2],[1,4],[1,6]] Explanation: The first 3 pairs are returned from the sequence: [1,2],[1,4],[1,6],[7,2],[7,4],[11,2],[7,6],[11,4],[11,6]
Example 2:
Input: nums1 = [1,1,2], nums2 = [1,2,3], k = 2 Output: [1,1],[1,1] Explanation: The first 2 pairs are returned from the sequence: [1,1],[1,1],[1,2],[2,1],[1,2],[2,2],[1,3],[1,3],[2,3]Example 3:
Input: nums1 = [1,2], nums2 = [3], k = 3 Output: [1,3],[2,3] Explanation: All possible pairs are returned from the sequence: [1,3],[2,3]
查找和最小的K对数字。
给定两个以升序排列的整形数组 nums1 和 nums2, 以及一个整数 k。
定义一对值 (u,v),其中第一个元素来自 nums1,第二个元素来自 nums2。
找到和最小的 k 对数字 (u1,v1), (u2,v2) ... (uk,vk)。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/find-k-pairs-with-smallest-sums
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
因为input数组是有序的,所以直觉上你会往双指针的思路上靠,但是后来发觉是不行的。如果面试官不指出你这个错误,TA十有八九是要挂你。因为题目给的是两个有序的数组,这个条件和容易让你往双指针的思路上凑。但是为什么不行呢?看第二个例子,一开始你肯定是两个数组各自的第一个元素拿出来组成第一个pair,但是之后呢,你怎么决定到底要移动哪个数组的指针呢?并不是说因着你用过了nums1[i]你就需要移动i,同理,并不是说你用过了nums2[j]你就要移动j。可以想象一个极端的例子,如果nums1的第一个元素非常非常小,然后nums2里面的元素都很大,很可能这K个pair里面都有nums1的这第一个元素。
正确的思路是用priority queue创建一个pair中两个数的和的最小堆,最后弹出K个pair即可。
时间O(nlogk)
空间O(n)
Java实现
1 class Solution { 2 public List> kSmallestPairs(int[] nums1, int[] nums2, int k) { 3 // corner case 4 List
> res = new ArrayList<>(); 5 if (nums1 == null || nums2 == null || nums1.length == 0 || nums2.length == 0) { 6 return res; 7 } 8 9 // normal case 10 PriorityQueue<int[]> queue = new PriorityQueue<>((a, b) -> (a[0] + a[1]) - (b[0] + b[1])); 11 for (int i = 0; i < Math.min(k, nums1.length); i++) { 12 for (int j = 0; j < Math.min(k, nums2.length); j++) { 13 queue.offer(new int[] {nums1[i], nums2[j]}); 14 } 15 } 16 while (k != 0 && !queue.isEmpty()) { 17 List
list = new ArrayList<>(); 18 int[] cur = queue.poll(); 19 list.add(cur[0]); 20 list.add(cur[1]); 21 res.add(list); 22 k--; 23 } 24 return res; 25 } 26 }
优化的思路是改成一个最大堆。还是先把所有的pair放入priority queue中,当这个优先队列的size小于K的时候,直接加入即可;但是当这个优先队列的size大于等于K了,但是此时还有元素需要加进去的时候,比较一下堆顶元素的sum和要加进去的元素的sum谁更大,抛弃掉更大的那个元素。最后优先队列里剩下前K小的元素。将这些元素再加入结果集中输出即可。
时间O(nlogk)
空间O(n)
Java实现
1 class Solution { 2 public List> kSmallestPairs(int[] nums1, int[] nums2, int k) { 3 // corner case 4 List
> res = new ArrayList<>(); 5 if (nums1 == null || nums2 == null || nums1.length == 0 || nums2.length == 0) { 6 return res; 7 } 8 9 // normal case 10 PriorityQueue<int[]> queue = new PriorityQueue<>((a, b) -> (b[0] + b[1]) - (a[0] + a[1])); 11 for (int i = 0; i < Math.min(k, nums1.length); i++) { 12 for (int j = 0; j < Math.min(k, nums2.length); j++) { 13 if (queue.size() < k) { 14 queue.offer(new int[] {nums1[i], nums2[j]}); 15 } else { 16 int sum = nums1[i] + nums2[j]; 17 int[] peek = queue.peek(); 18 int peekSum = peek[0] + peek[1]; 19 if (sum < peekSum) { 20 queue.poll(); 21 queue.offer(new int[] {nums1[i], nums2[j]}); 22 } 23 } 24 } 25 } 26 while (k != 0 && !queue.isEmpty()) { 27 List
list = new ArrayList<>(); 28 int[] cur = queue.poll(); 29 for (int num : cur) { 30 list.add(num); 31 } 32 res.add(list); 33 k--; 34 } 35 return res; 36 } 37 }
LeetCode 题目总结