373. 查找和最小的K对数字
给定两个以升序排列的整数数组 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
大顶堆排序
思路
思路1:暴力例举,内存不够 思路2:只保留k个元素,每次插入排序,超时 思路3:大顶堆 通过
这里我们使用一个大顶堆来存储k个元素
- 使用双循环来找到所有的组合
- 判断堆的数量,如果不够k个则继续push,如果大于k个则需要判断
如果新元素的值小于堆中的最大值,那么push进去,堆中的元素,重新排列一下(只需要挪动很少次数,每次与父节点进行比较即可)
- 最后得到一个size为k的大顶堆
最后循环取出大顶堆中的没一个元素返回即可
class Heap {
constructor(data, compare) {
this.data = data;
this.compare = compare;
for (let i = (data.length >> 1) - 1; i >=0 ; i--) {
this.heapify(i);
}
}
heapify(index) {
let target = index;
let left = index * 2 + 1;
let right = index * 2 + 2;
if (left < this.data.length && this.compare(this.data[left], this.data[target])) {
target = left;
}
if (right < this.data.length && this.compare(this.data[right], this.data[target])) {
target = right;
}
if (target !== index) {
this.swap(target, index);
this.heapify(target);
}
}
swap(l, r) {
let data = this.data;
[data[l], data[r]] = [data[r], data[l]];
}
push(item) {
this.data.push(item);
let index = this.data.length - 1;
let father = ((index + 1) >> 1) - 1;
while (father >= 0) {
if (this.compare(this.data[index], this.data[father])) {
this.swap(index, father);
index = father;
father = ((index + 1) >> 1) - 1;
} else {
break;
}
}
}
pop() {
this.swap(0, this.data.length - 1);
let ret = this.data.pop();
this.heapify(0);
return ret;
}
}
var kSmallestPairs = function(nums1, nums2, k) {
let total = [];
let pq = new Heap([], (lower, higher) => lower.val > higher.val);
for (let i = 0; i < nums1.length; i++) {
for (let j = 0; j < nums2.length; j++) {
if (pq.data.length == k && (nums1[i] + nums2[j] > pq.data[0].val)) {
break;
}
pq.push({
val: nums1[i] + nums2[j],
item: [nums1[i], nums2[j]]
});
if(pq.data.length > k) {
pq.pop();
}
}
}
let ret = [];
while (pq.data.length) {
ret.unshift(pq.pop().item);
}
return ret;
};