题目描述
给定两个以升序排列的整数数组 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
来源:力扣(LeetCode) 链接:leetcode-cn.com/problems/fi… 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
解题思路
根据题目,我们需要返回最小的k组数据,所以我们只需要维护包含k个最小值的数组就行。
优先队列:
- 最小优先队列,维护一个最大长度为k的队列list,每个元素为由nums1的第i个元素和nums2的第j个元素组成的数组。即[nums1[i],nums2[j]],并按优先级排列元素。
- 由题干要求知,和越小的优先级越高,所以排在队列前面。遇到相同的后来的排后面
- 双重遍历两个数组,得到所有组合
- list长度小于k时,把元素按以上优先级加入到合适的位置(遍历list找到和更大的元素,插入这个元素前面,如果没有比现在大的,就加到队列最后)
- list大于k时,还是执行以上插入动作,然后从队列尾部删除一个和最大的组合
- 遍历时,可以通过一些判断减少遍历数量,比如数组都是升序排列的,所以在遍历nums2时,如果list已经满了,且(nums2[j]+nums1[i])值比list末尾元素和值还大,就可以break跳出循环,直接进入下个循环。
代码
/**
*
* @param {number[]} nums1
* @param {number[]} nums2
* @param {number} k
* @return {number[][]}
*/
var kSmallestPairs = function(nums1, nums2, k) {
this.list=[];//用来保存前k小组合的队列
let last=null;//记录队列满了之后最大值
for(let i=0;i<nums1.length;i++){
for(let j=0;j<nums2.length;j++){
// 如果当前的i+j已经大于队列的最大值就没必要继续遍历了
if(last&&this.list.length>=k&&(nums2[j]+nums1[i])>last){
break;
}
//遍历所有结果,执行添加操作
add([nums1[i],nums2[j]],this.list,k);
//添加过后超出k了,就删除最后一个,最后一个最大
if(this.list.length>k){
this.list.pop();
last=this.list[this.list.length-1][0]+this.list[this.list.length-1][1]
}
}
// 如果当前的i+j已经大于队列的最大值就没必要继续遍历了
if(last&&this.list.length>=k&&(nums1[i]+nums2[0])>last){
break;
}
}
return this.list;
};
/**添加元素
*/
var add=function(item,list,k){
if(list.length===0){
list.push(item);
return;
}
//如果这个元素比栈尾大就直接淘汰(元素满的时候)
if(list.length>=k&&compare(item,list[list.length-1])) return;
//按组合元素之和从小到大的优先级入队
for(let i=0;i<list.length;i++){
if(compare(list[i],item)){
//找到比自己大的元素,就排他前面
list.splice(i,0,item);
return;
}
}
//遍历结束还没找到比大的就呆在末尾
list.push(item);
}
/**比较两个集合元素相加大小,前大于后返回true
*/
function compare(item1,item2){
return (item1[0]+item1[1])> (item2[0]+item2[1])
}