[LeetCode]373. Find K Pairs with Smallest Sums 动态规划解法转移方程
题目描述
LeetCode原题链接:373. Find K Pairs with Smallest Sums
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.
Return 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]
Constraints:
1 <= nums1.length, nums2.length <= 105-109 <= nums1[i], nums2[i] <= 109nums1andnums2both are sorted in ascending order.1 <= k <= 104
思路分析
这道题brute force的思路很清晰,就是去穷举所有可能的pair,然后把这些pair存放到MinPriorityQueue中,或者存放到一个array之后排序,最终结果返回前k个。
1 for(let u of nums1) { 2 for(let v of nums2) { 3 minPriorityQueue.enqueue(u + v) 4 } 5 }
那么有没有效率更高一点的方法呢?
提高效率的关键在于如何从nums1和nums2中选取数字组成pair,题目中强调了nums1和nums2都是递增顺序的数组,那么我们想啊,要想让取出的两个数和最小,肯定两个数就要分别是数组中较小的数。brute force中我们是先锁定nums1中某一位置的数作为u,然后去遍历nums2中所有的数来找v,显然越往后v肯定越大,虽然u是nums1中当前循环里较小的数,但是v可能会很大,显然不如重新去取nums1中第二小的数和nums2中前部分的数。
所以,关键就是怎么在nums2中找v,也就是该从哪个位置开始找v。这里我们可以用一个数组idx[i]来表示当u=nums1[i]时,应当从nums2的哪个位置开始去寻找v,idx中的元素初始化为0;
我们每次从i=0位置开始遍历nums1数组中的全部元素,用两个变量cur和sum分别记录局部最小值,cur初始化为0, sum初始化为Number.MAX_VALUE, 那么对应 u=nums1[i] 的v就是 nums2[idx[i]],u+v 需要注意,因为idx[i]表示的是nums2中的下标。所以前提肯定是 idx[i] < nums2.length. 另外,我们知道最多可以组成的pair个数是nums1和nums2数组长度的乘积。那么结果数组的长度就是min(k, nums1.length * nums2.length);我们用一个while循环来寻找这些数。代码示例(JS)
1 var kSmallestPairs = function(nums1, nums2, k) {
2 k = Math.min(k, nums1.length * nums2.length);
3 let idx = new Array(nums1.length);
4 idx.fill(0);
5 let res = [];
6 while(k-- > 0){
7 let cur = 0, sum = Number.MAX_VALUE;
8 for(let i = 0; i < nums1.length; i++) {
9 if(idx[i] < nums2.length && nums1[i] + nums2[idx[i]] < sum) {
10 sum = nums1[i] + nums2[idx[i]];
11 cur = i;
12 }
13 }
14 res.push([nums1[cur], nums2[idx[cur]]]);
15 idx[cur]++;
16 }
17 return res;
18 };