[路飞]_程序员必刷力扣题: 373. 查找和最小的K对数字

125 阅读1分钟

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;
};