• [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] <= 109
    • nums1 and nums2 both 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<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 };
  • 相关阅读:
    Http错误代码
    Android View自动生成插件
    【Android】设备标识
    【Android】键盘的展开和收起
    【Android】Activity生命周期(亲测)
    【Android】IntentService & HandlerThread源码解析
    【Android】与服务器实现JSON数据通信
    【Web】Eclipse + Maven + Struts搭建服务器
    【Android】Kill Service
    【Android】Handler、Looper源码分析
  • 原文地址:https://www.cnblogs.com/barryyeee/p/16053074.html
Copyright © 2020-2023  润新知