ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

373. 查找和最小的K对数字

2020-03-02 10:58:51  阅读:314  来源: 互联网

标签:int memo 最小 查找 vector 373 nums1 nums2 cmp


题目:

链接:https://leetcode-cn.com/problems/find-k-pairs-with-smallest-sums/

给定两个以升序排列的整形数组 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:

直接套用TOP-K问题的解法(https://www.cnblogs.com/FdWzy/p/12321325.html

由于求最小的k个元素对,那么首先定义小于重载关系。

之后利用最大堆,堆大小不超过k直接push,超过k要看是否比堆顶小,是则pop并push,否则跳过。

效率O(m*n*log k)

 

 1 class Solution {
 2 public:
 3     vector<vector<int>> kSmallestPairs(vector<int>& nums1, vector<int>& nums2, int k) {
 4         vector<vector<int>> res;
 5         int len1=nums1.size(),len2=nums2.size();
 6         auto cmp=[](vector<int>& a,vector<int>& b){return a[0]+a[1]<b[0]+b[1];};
 7         priority_queue<vector<int>,vector<vector<int>>,decltype(cmp)> max_heap(cmp);
 8         vector<int> tmp1,tmp2;
 9         for(int i=0;i<len1;++i){
10             for(int j=0;j<len2;++j){
11                 if(max_heap.size()<k){
12                     max_heap.push({nums1[i],nums2[j]});
13                 }
14                 else{
15                     tmp1=max_heap.top();
16                     tmp2={nums1[i],nums2[j]};
17                     if(not cmp(tmp1,tmp2)){
18                         max_heap.pop();
19                         max_heap.push(move(tmp2));
20                     }
21                 }
22             }
23         }
24         while(not max_heap.empty()){
25             res.emplace_back(max_heap.top());
26             max_heap.pop();
27         }
28         reverse(res.begin(),res.end());
29         return res;
30     }
31 };

 

 

 

 

方法2:

前一个方法比较暴力,直接枚举所有可能的元素对全部加入最大堆进行筛选。这样呢,没有利用两个数组有序的性质,两个无序数组也可以这样做。

所以我们考虑记录对于每一个nums1中的索引i,如果已经把[i,0],[i,1],[i,2]...[i,j]全部的元素对加入了结果,那么下次再查找[i,xx]元素对的时候,就可以从j+1开始找,因为数组是有序的。

 

用一个memo数组记录。

做法,我们这回用最小堆,堆顶直接指示为最小的元素对。每次取堆顶,更改相应的memo数组值。如果memo[i]=len(nums2),那说明[i,xx]元素对已经无法再取了,就直接从堆中删掉。

如果memo[i]<len(nums2),那么再push回堆里。

效率:O(m*log m+k*log m)

 1 class Solution {
 2 public:
 3     vector<vector<int>> kSmallestPairs(vector<int>& nums1, vector<int>& nums2, int k) {
 4         vector<vector<int>> res;
 5         int len1=nums1.size(),len2=nums2.size();
 6         if(len1==0 or len2==0){return res;}
 7         vector<int> memo(len1,-1);
 8         //memo[i]指示:{nums1[i],nums2[j]}元素对中上次已经放入结果数组那个的j的值,i对应第一个未使用的j为memo[i]+1
 9         auto cmp=[&](int x,int y){return nums1[x]+nums2[memo[x]+1]>nums1[y]+nums2[memo[y]+1];};
10         priority_queue<int,vector<int>,decltype(cmp)> min_heap(cmp);//小顶堆
11         for(int i=0;i<len1;++i){
12             min_heap.push(i);
13         }
14         while(res.size()<k and not min_heap.empty()){//每次循环把小顶堆的堆顶(也就是目前的最小对)push进结果
15             int tp=min_heap.top();
16             min_heap.pop();
17             res.push_back({nums1[tp],nums2[memo[tp]+1]});
18             memo[tp]+=1;                            //memo[tp]+1已经遍历,所以memo[tp]+=1;
19             if(memo[tp]<len2-1){                    //如果tp对应nums2中的索引到达nums2尾部,那就不push了
20                 min_heap.push(tp);
21             }
22         }
23         return res;
24     }
25 };

 

标签:int,memo,最小,查找,vector,373,nums1,nums2,cmp
来源: https://www.cnblogs.com/FdWzy/p/12394265.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有