其他分享
首页 > 其他分享> > [LeetCode]373. Find K Pairs with Smallest Sums 动态规划解法转移方程

[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:

思路分析

这道题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<sum 时去更新cur为i,sum为u+v,nums1遍历结束后就是当前要找的和最小的pair。将 [nums1[cur], nums2[idx[cur]]] 加入res数组,同时去更新 idx[cur] 为 idx[cur]+1 , 表明nums2中这个位置的数已经和nums1中cur位置的数组成过一个符合要求的pair了,不能够再使用了;下一轮nums1再遍历到这个位置的时候,nums2中v要从该位置后面的数中去寻找。idx数组是这个算法剪枝的关键。

需要注意,因为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 };

标签:Pairs,cur,idx,Sums,nums1,length,let,Find,nums2
来源: https://www.cnblogs.com/barryyeee/p/16053074.html