• [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.

    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数组是有序的,所以直觉上你会往双指针的思路上靠,但是后来发觉是不行的。为什么不行呢?看第二个例子,一开始你肯定是两个数组各自的第一个元素拿出来组成第一个pair,但是之后呢,你怎么决定到底要移动哪个数组的指针呢?并不是说因着你用过了 nums1[i] 你就需要移动 i,同理,并不是说你用过了 nums2[j] 你就要移动 j。同时注意 i 指针和 j 指针可以指向同一个下标。可以想象一个极端的例子,如果 nums1 的第一个元素非常非常小,然后 nums2 里面的元素都很大,很可能这 K 个 pair 里面都有 nums1 的这第一个元素。

    正确的思路是用priority queue创建一个 pair 中两个数的和的最小堆,最后弹出K个 pair 即可。

    时间O(nlogk)

    空间O(n)

    Java实现

     1 class Solution {
     2     public List<List<Integer>> kSmallestPairs(int[] nums1, int[] nums2, int k) {
     3         // corner case
     4         List<List<Integer>> 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<Integer> 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<List<Integer>> kSmallestPairs(int[] nums1, int[] nums2, int k) {
     3         // corner case
     4         List<List<Integer>> 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<Integer> 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 }

    相关题目

    373. Find K Pairs with Smallest Sums

    378. Kth Smallest Element in a Sorted Matrix

    719. Find K-th Smallest Pair Distance

    LeetCode 题目总结

  • 相关阅读:
    linux常用命令
    Python 父类调用子类方法
    import win32api 安装pip install pypiwin32
    Python 封装DTU-215码流卡 第一天
    git apply -v 提示 Skipped patch 打不上patch的解决办法
    2019/10/29
    12/9/2019
    11/9/2019
    9/7/2019
    人生若有命中注定
  • 原文地址:https://www.cnblogs.com/cnoodle/p/13409243.html
Copyright © 2020-2023  润新知