📅  最后修改于: 2023-12-03 15:40:02.961000             🧑  作者: Mango
给定两个有序整数数组 nums1 和 nums2,请找出数组中最小的 k 个数对(u,v),其中第一个数组来自 nums1,第二个数组来自 nums2。
例如,给定如下两个数组:
nums1 = [1,7,11], nums2 = [2,4,6], k = 3
返回如下 3 个数对:
[1,2],[1,4],[1,6]
可以将数对全部找出来并排序,然后取前k个。
时间复杂度:$O(n^2 \log n)$。
在数组 nums1 中选一个数,再在数组 nums2 中选一个数,组成一个数对。这样得到的数字对的总数为 m*n,其中 m 和 n 为两个数组的长度。
现在的问题是,如何在所有的数对中找到最小的 k 个数对?一个显然的思路是将所有的数对排序,并取其前 k 个。但是,如果数组长度较大时,这样的时间复杂度会很高($O(mn \log mn)$)。
为了优化时间复杂度,我们可以考虑一次取出多个数对,然后从中选出最小的数对。
具体地,我们可以使用一个最小堆来存储当前所有的包含 nums1 中的数和 nums2 中的数的数对。初始时,只将 (0,0) 加入到最小堆中。每次从最小堆中取出一个数对 (i,j),并将其加入结果中,同时将 (i+1,j) 和 (i,j+1) 这两个数对加入最小堆中。如此重复 k 次,则可以得到前 k 个最小的数对。
此方法时间复杂度为 $O(k \log k)$。
def kSmallestPairs(nums1, nums2, k):
pairs = []
for num1 in nums1:
for num2 in nums2:
pairs.append((num1, num2))
pairs.sort(key=lambda x: x[0] + x[1])
return pairs[:k]
import heapq
def kSmallestPairs(nums1, nums2, k):
if not nums1 or not nums2:
return []
pqueue = [(nums1[0]+nums2[0], 0, 0)]
res = []
while pqueue and len(res) < k:
_, i, j = heapq.heappop(pqueue)
res.append([nums1[i], nums2[j]])
if i+1 < len(nums1) and j == 0:
heapq.heappush(pqueue, (nums1[i+1]+nums2[0], i+1, 0))
if j+1 < len(nums2):
heapq.heappush(pqueue, (nums1[i]+nums2[j+1], i, j+1))
return res
本题解介绍了两种解法,暴力和最小堆。其中最小堆方法的时间复杂度为 $O(k \log k)$,优于暴力方法的时间复杂度 $O(mn \log mn)$,但需要额外的空间来存储堆。