[路飞]_leetcode-373-查找和最小的K对数字

简介: leetcode-373-查找和最小的K对数字

网络异常,图片无法展示
|


[题目地址][B站地址]


给定两个以升序排列的整数数组 nums1 和 ****nums2 ****, 以及一个整数 k ****。

定义一对值 (u,v),其中第一个元素来自 nums1,第二个元素来自 nums2 ****。

请找到和最小的 k 个数对 (u1,v1), (u2,v2)  ...  (uk,vk)


示例 1:


输入: nums1 = [1,7,11], nums2 = [2,4,6], k = 3
输出: [1,2],[1,4],[1,6]
解释: 返回序列中的前 3 对数:
     [1,2],[1,4],[1,6],[7,2],[7,4],[11,2],[7,6],[11,4],[11,6]
复制代码


示例 2:


输入: nums1 = [1,1,2], nums2 = [1,2,3], k = 2
输出: [1,1],[1,1]
解释: 返回序列中的前 2 对数:
     [1,1],[1,1],[1,2],[2,1],[1,2],[2,2],[1,3],[1,3],[2,3]
复制代码


示例 3:


输入: nums1 = [1,2], nums2 = [3], k = 3 
输出: [1,3],[2,3]
解释: 也可能序列中所有的数对都被返回:[1,3],[2,3]
复制代码


提示:


  • 1 <= nums1.length, nums2.length <= 104
  • -109 <= nums1[i], nums2[i] <= 109
  • nums1, nums2 均为升序排列
  • 1 <= k <= 1000


涉及到求 k 个最值得问题,都可以利用堆这种数据结构来解题。


这里因为是要维护前 k 个最小数对,所以需要一个大顶堆。


解题思路如下:


  1. 实例化一个大顶堆
  2. 两层循环找出所有可能的数对
  3. 如果堆中数量不够 k 个或者当前数对之和小于堆顶数对之和,则将当前数对入堆
  4. 如果当前数对之和大于堆顶数对之和,则退出本次循环。因为两个数组都是升序排列的,如果当前数对之和大于堆顶数对之和,则后续数对之和肯定也大于堆顶数对之和,所以无需继续遍历。
  5. 最后堆中保存的就是前k 个最小的数对


代码如下:


// 实现大顶堆
class BigHeap {
  constructor(k){
    this.arr = [];
    this.size = 0;
    this.max = k;
  }
  // 插入操作
  push(item){
    this.arr.push(item);
    this.size++;
    if(this.size>1){
      let cur = this.size-1,
      parent = (cur-1)>>1;
      while(cur>0&&compare(this.arr[cur],this.arr[parent])){
        [this.arr[parent],this.arr[cur]] = 
        [this.arr[cur],this.arr[parent]];
        cur = parent;
        parent = (cur-1)>>1;
      }
    }
    if(this.size>this.max) this.pop();
  }
  // 弹出操作
  pop(){
    this.arr[0] = this.arr.pop();
    this.size--;
    let cur = 0,
    childl = cur*2+1,
    childr = cur*2+2;
    while(
      (childl<this.size&&compare(this.arr[childl],this.arr[cur])) ||
      (childr<this.size&&compare(this.arr[childr],this.arr[cur]))
    ){
      if(childr<this.size&&compare(this.arr[childr],this.arr[childl])){
        [this.arr[cur],this.arr[childr]] = 
        [this.arr[childr],this.arr[cur]];
        cur = childr;
      }else{
        [this.arr[cur],this.arr[childl]] = 
        [this.arr[childl],this.arr[cur]];
        cur = childl;
      }
      childl = cur*2+1,
      childr = cur*2+2;
    }
  }
  // 获取堆顶元素
  top(){
    return this.arr[0]
  }
}
// 比较两数组之和大小
function compare(arr1,arr2){
  return (arr1[0]+arr1[1])>(arr2[0]+arr2[1])
}
var kSmallestPairs = function(nums1, nums2, k) {
  // 实例化大顶堆
  const heap = new BigHeap(k);
  // 遍历每一种组合
  for(let i = 0;i<nums1.length;i++){
    for(let j = 0;j<nums2.length;j++){
      const item = [nums1[i],nums2[j]];
      // 只有当堆中元素数量小于k个或者当前数对之和小于堆顶元素时才插入堆中
      if(heap.size<k || compare(heap.top(),item)){
        heap.push(item);
      }else{
        // 如果当前数对大于堆顶元素,那么本次循环后续数对也一定大于堆顶元素,退出当前循环
        break;
      }
    }
  }
  // 返回堆中保存数对
  return heap.arr;
};
复制代码


至此我们就完成了 leetcode-373-查找和最小的K对数字


如有任何问题或建议,欢迎留言讨论!

相关文章
|
3天前
|
存储 算法
LeetCode刷题---209. 长度最小的子数组(双指针-滑动窗口)
LeetCode刷题---209. 长度最小的子数组(双指针-滑动窗口)
|
3天前
|
算法 测试技术 C++
二分查找|滑动窗口|前缀和|LeetCode209: 长度最小的子数组
二分查找|滑动窗口|前缀和|LeetCode209: 长度最小的子数组
|
3天前
剑指Offer LeetCode 面试题40. 最小的k个数
剑指Offer LeetCode 面试题40. 最小的k个数
23 0
|
3天前
|
Java C++ Python
leetcode-209:长度最小的子数组
leetcode-209:长度最小的子数组
24 0
|
3天前
leetcode代码记录(长度最小的子数组
leetcode代码记录(长度最小的子数组
10 0
|
7月前
|
机器学习/深度学习 算法
代码随想录Day02 数组基础2 leetcode T977有序数组的平方, T209 长度最小的子数组,T59 螺旋矩阵II
代码随想录Day02 数组基础2 leetcode T977有序数组的平方, T209 长度最小的子数组,T59 螺旋矩阵II
35 0
|
3天前
|
算法 测试技术
每日一题:LeetCode-209. 长度最小的子数组(滑动窗口)
每日一题:LeetCode-209. 长度最小的子数组(滑动窗口)
|
3天前
|
存储
【Leetcode 209】长度最小的子数组 —— 滑动窗口|双指针
我们可以使用双指针解决本题,定义两个指针 i 和 j 分别表示子数组(滑动窗口窗口)的开始位置和结束位置,维护变量 sum 存储子数组中的元素和。每一轮迭代中,每当 sum >= target 则记录子数组最小长度,移动慢指针。在每一轮迭代最后,移动快指针
|
3天前
|
算法 测试技术 C#
二分查找|滑动窗口|前缀和|LeetCode209: 长度最小的子数组
二分查找|滑动窗口|前缀和|LeetCode209: 长度最小的子数组
|
3天前
leetcode-373:查找和最小的 K 对数字
leetcode-373:查找和最小的 K 对数字
21 0