Question:
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:
Given nums1 = [1,7,11], nums2 = [2,4,6], k = 3
Return: [1,2],[1,4],[1,6]
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:
Given nums1 = [1,1,2], nums2 = [1,2,3], k = 2
Return: [1,1],[1,1]
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:
Given nums1 = [1,2], nums2 = [3], k = 3
Return: [1,3],[2,3]
All possible pairs are returned from the sequence:
[1,3],[2,3]
Solution:
class Solution {
public:
vector<pair<int, int>> kSmallestPairs(vector<int>& nums1, vector<int>& nums2, int k) {
vector<pair<int,int>> res;
if(nums1.empty() || nums2.empty() || k == 0){
return res;
}
vector<pair<int,int>> tmp;
int l1 = nums1.size();
int l2 = nums2.size();
//第一步,将所有可能的pair读入
for(int i = 0 ; i < l1;i++){
for(int j = 0 ; j < l2; j++){
tmp.push_back(make_pair(nums1[i],nums2[j]));
}
}
//构造小顶堆
buildheap(tmp);
int ltmp = tmp.size();
for(int i = 0 ; i<k&&i<ltmp;i++){//找到k对或者小顶堆读尽结束
res.push_back(tmp[0]);
tmp[0] = tmp.back();
tmp.pop_back();
heap(tmp,0);
}
return res;
}
void buildheap(vector<pair<int,int>>& nums){
int len = nums.size();
for(int i = len/2 ; i >= 0;i--){//由中间的位置开始,也就是从最后一个元素开始,将最小数往上冒
heap(nums,i);
}
}
void heap(vector<pair<int,int>>& nums,int i){
int len = nums.size();
int msum = nums[i].first+nums[i].second;
int min = i;
int l = (i<<1) + 1;
int r = l+1;
if(l < len && nums[l].first+nums[l].second < msum){
min = l;
msum = nums[l].first+nums[l].second;
}
if(r < len && nums[r].first+nums[r].second < msum){
min = r;
}//在该元素和他两个孩子中找到最小
pair<int,int> tmp = nums[min];
nums[min] = nums[i];
nums[i] = tmp;//将最小元素放置在双亲位置
if(min != i){//确保该元素在正确的位置
heap(nums,min);
}
}
};
总结:
三个注意点:
- 起始索引为0的情况,其左右孩子索引为2i+1和2i+2,而不是2i和2i+1!!
- 使用 移位符号时,比如 i<<1+1,注意+优先级大于<<,所以结果为 i 左移 2 位,并非 i 左移 1 位 加 1.
- 构造小顶堆的时候,循环要从len/2递减,而不是由0到len/2递增。第二种情况最终的结果只能保证最大值在叶子节点,并不能保证堆顶是最小值。