持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第10天,点击查看活动详情
LeetCode每日一题打卡专栏正式启动!不出意外将日更LeetCode的每日一题,敬请期待。
373:查找和最小的K对数字
题意
给定两个以 升序排列 的整数数组 和 , 以及一个整数 。
定义一对值 (u,v),其中第一个元素来自 ,第二个元素来自 。
请找到和最小的 k 个数对 , ... 。
示例
示例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]
提示:
- 和均为升序排列
题解:优先队列
由于题目所求为前k个最小的数对,同时两个数组均为升序排列,所以最小的一定为,次小的必定在之中,而具体是哪个需要判断:
- 如果直接二重循环暴力判断,题目给定数组长度为显然不行
- 考虑用数据结构存储,从而判断哪个次小,于是首选优先队列
如果优先队列存储和的值的话,可能会出现重复,于是优先队列只存储和的下标.
因为题目只需要前k个最小的,于是最多只需要出队k次即可。
- 时间复杂度:O(klogk) (因为需要出队k次,同时每次入队需要logk的时间复杂度)
- 空间复杂度:O(k)
C++代码:
!!记得a,b数组初始置空,LeetCode判题机到现在还没摸清
vector<int> a,b;
class Solution {
public:
struct node{
int u,v;
bool operator < (const node p) const{
return a[u]+b[v] > (a[p.u]+b[p.v]);
}
};
vector<vector<int>> kSmallestPairs(vector<int>& nums1, vector<int>& nums2, int k) {
a.clear();b.clear();
int n=nums1.size(),m=nums2.size();
for(int i=0;i<n;i++) a.push_back(nums1[i]);
for(int i=0;i<m;i++) b.push_back(nums2[i]);
vector<vector<int> >ans;
//定义优先队列,存储两数组元素下标
priority_queue<node> q;
//先nums1所有的下标入队
for(int i=0;i<min(k,n);i++){
q.push(node{i,0});
}
//最多出队k次
while(k>0&&!q.empty()){
node now=q.top();q.pop();
vector<int> ve;ve.push_back(nums1[now.u]);ve.push_back(nums2[now.v]);
ans.push_back(ve);
//nums2数字下标右移一位,然后入队
if(++now.v<m)
q.push(node{now});
k--;
}
return ans;
}
};
Java代码:
class Solution {
public List<List<Integer>> kSmallestPairs(int[] nums1, int[] nums2, int k) {
//返回值
List<List<Integer>> ans=new ArrayList<>();
//定义优先队列存储两数组下标
PriorityQueue<int[]> q=new PriorityQueue<>((a,b) ->
nums1[a[0]]+nums2[a[1]]-(nums1[b[0]]+nums2[b[1]]));
//首先将nums1数组下标入队(因为不需要只需要入队k个即可,所以取个最小值)
for(int i=0;i<Math.min(k, nums1.length);i++){
q.add(new int[]{i,0});
}
//最多弹出k次
while(k>0&&!q.isEmpty()){
int[] a=q.poll();
//返回当前最小的和
List now=new ArrayList<>();
now.add(nums1[a[0]]);now.add(nums2[a[1]]);
ans.add(now);
//nums2数组下标右移,然后继续入队
if(++a[1]<nums2.length)
q.add(a);
k--;
}
return ans;
}
}