leetcode 每日一题
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]
三叶姐姐的多路归并题解
(三叶姐姐yyds:https://leetcode-cn.com/u/ac_oier/)
class Solution {
boolean flag = true;
public List<List<Integer>> kSmallestPairs(int[] nums1, int[] nums2, int k) {
List<List<Integer>> ans = new ArrayList<>();
int n = nums1.length, m = nums2.length;
if (n > m && !(flag = false)) return kSmallestPairs(nums2, nums1, k);
PriorityQueue<int[]> q = new PriorityQueue<>((a, b)->(nums1[a[0]]+nums2[a[1]])-(nums1[b[0]]+nums2[b[1]]));
for (int i = 0; i < Math.min(n, k); i++) q.add(new int[]{
i, 0});
while (ans.size() < k && !q.isEmpty()) {
int[] poll = q.poll();
int a = poll[0], b = poll[1];
ans.add(new ArrayList<>(){
{
add(flag ? nums1[a] : nums2[b]);
add(flag ? nums2[b] : nums1[a]);
}});
if (b + 1 < m) q.add(new int[]{
a, b + 1});
}
return ans;
}
}
多路归并
百度百科的简介:
(1) 假设有K路数据流,流内部是有序的,且流间同为升序或降序;
(2) 首先读取每个流的第一个数,如果已经EOF,pass;
(3) 将有效的k(k可能小于K)个数比较,选出最小的那路mink,输出,读取mink的下一个;
(4) 直到所有K路都EOF。
方法一:
首先,我们比较所有k个数组的头一个元素,找到最小的那一个,然后取出来。我们在该最小元素所在的数组取下一个元素,然后重复前面的过程去找最小的那个。这样依次循环直到找到所有的元素。
用一个notEmpty来标志所有序列是否已经遍历完了。每次遍历所有序列的当前元素,找到最小的。这样每次找一个元素都要比较k次,假设所有n个元素,其总体时间复杂度就达到了O(nk)。
方法二:
首先从k路序列中都取一个元素出来。因为所有的都是已经按照从小到大排序的,不需要考虑其他的。每个序列里取出来的肯定是这个序列里最小的,在这些最小元素里找到全局最小的那个。针对这个序列后面是否还有元素的问题,可以通过以下两种方法处理:
-
假定在处理元素的过程中,某个序列的元素取光了。我们可以在开始的时候针对所有序列的最后都加一个表示无穷大的数值。这样如果取完这个序列之后可以保证它后续肯定不会被选择到。
-
我们将该元素用堆最后的元素替换,然后调整堆的属性并将堆的大小减1。这样我们这个大小为k的堆慢慢会变成k-1, k-2,1这些个长度的堆。一直到我们把这些堆里序列的元素处理完
优先队列
听这个名字就能知道,优先队列也是一种队列,只不过不同的是,优先队列的出队顺序是按照优先级来的;在有些情况下,可能需要找到元素集合中的最小或者最大元素,可以利用优先队列ADT来完成操作,优先队列ADT是一种数据结构&