373.查找和最小的k对数字
✨ 373.查找和最小的k对数字
给定两个以 非递减顺序排列 的整数数组 nums1
和 nums2
, 以及一个整数 k
。
定义一对值 (u,v)
,其中第一个元素来自 nums1
,第二个元素来自 nums2
。
请找到和最小的 k
个数对 (u1,v1)
, (u2,v2)
… (uk,vk)
。
思路
基本思想
为了求出所有符合要求的数对,最简单的办法就是先将所有的数对先求出来,然后再利用堆排序求出前k个数对,但是这样时间复杂度太高,主要的问题就是出在要将所有的数对都求出来,出现了很多的冗余,其实完全可以只求出部分数对,这里有一个前提,最小的数对的索引一定是[0,0]
,最大的数对的索引一定是[nums1.length,nums2.length]
,而当选择了第n个数对之后,下一个数对的索引是在当前数对的索引基础上递增得来的。假设当前数对的索引为[x,y]
,那么下一个数对的候选索引一定是[x+1,y]
和[x,y+1]
。
有了索引递增的概念之后,为了求出前k个和最小的数对,我们直接将索引加入优先级队列中,比较规则是当前的索引对应的数对和小的元素在前面,大的元素在后面,这样每次取出来的都是当前最小的数对。在取出一个数对元素之后,需要加入下一个候选的数对,此时需要注意,不能直接加入,否则会出现重复元素
例如当前选择的索引为[1,2],那么加入的候选数对为[1,3]和[2,2],如果后面某一步选择了[2,1],那么就会重复加入[2,2]这个数对,这是因为数对的索引是同步变化的,没有固定住其中一个,为了去掉重复索引,我们选择将其中一个索引固定住,也就是先将部分元素加入优先级队列
|
|
加入之后,第一个位置的索引固定为最大值,这样就不会同步变化,也就不会出现重复的索引了
核心就是利用优先级队列可以对元素排序的思想,每次从中取出当前和最小的数对,并将下一步的候选下标加入
类似的题目还有 786. 第 K 个最小的素数分数
执行流程
- 设计一个优先级队列,排序规则根据下标对应的数对和的大小升序排列
- 先将部分下标加入优先级队列中,目的是为了固定一个下标不变,防止两个下标同时变化导致出现重复元素
- 每次从优先级队列中取出当前最小的数对元素,然后加入下一步的候选元素
- 取出k对元素之后返回最终的结果即可
代码
|
|
总结
核心就是利用优先级队列存储数对的下标,然后排序规则按照数对和的大小升序排列,为了解决重复元素的问题,先将部分下标组合加入队列中,重点需要注意上面描述中的 “假设当前数对的索引为[x,y]
,那么下一个数对的候选索引一定是[x+1,y]
和[x,y+1]
。”