返回
LeetCode373 查找和最小的 K 对数字:TopK 问题:「小根堆 & 多路归并」 |「二分 & 滑动窗口」
闲谈
2023-09-09 13:53:06
LeetCode 373 查找和最小的 K 对数字
题目
给定两个以升序排列的有序数组 nums1 和 nums2,以及一个整数 k,找到并返回nums1 和 nums2 的前 k 个最小的数对。
示例
输入:nums1 = [1, 7, 11], nums2 = [2, 4, 6], k = 3
输出:[[1, 2], [1, 4], [1, 6]]
解释:前 k 个最小的数对是:[1, 2], [1, 4], [1, 6]。
算法
小根堆
小根堆是一种数据结构,其中每个节点的值都小于或等于其子节点的值。我们可以使用小根堆来存储nums1和 nums2 的前 k 个最小的数对。
- 将nums1和 nums2 中的所有数对添加到小根堆中。
- 重复以下步骤 k 次:
- 从小根堆中弹出最小的数对。
- 将这个数对添加到输出中。
多路归并
多路归并是一种将多个有序数组合并为一个有序数组的算法。我们可以使用多路归并来合并nums1和 nums2,然后从合并后的数组中找到前 k 个最小的数对。
- 将nums1和 nums2 合并为一个有序数组。
- 从合并后的数组中找到前 k 个最小的数对。
二分
二分是一种在有序数组中查找特定元素的算法。我们可以使用二分来查找nums1和 nums2 中的第 k 个最小的数对。
- 将nums1和 nums2 合并为一个有序数组。
- 使用二分找到合并后的数组中第 k 个最小的数对。
滑动窗口
滑动窗口是一种在数组中查找特定元素的算法。我们可以使用滑动窗口来查找nums1和 nums2 中的前 k 个最小的数对。
- 创建一个大小为 k 的滑动窗口,并将窗口放在nums1和 nums2 中的第一个数对上。
- 重复以下步骤 k 次:
- 找到窗口中所有数对中最小的数对。
- 将这个数对添加到输出中。
- 将窗口向右移动一个位置。
比较
这四种算法的复杂度如下:
- 小根堆:O((m + n) log k)
- 多路归并:O((m + n) log (m + n))
- 二分:O((m + n) log (m + n))
- 滑动窗口:O(m + n)
其中,m 和 n 分别是 nums1 和 nums2 的长度。
在实践中,滑动窗口算法通常是这四种算法中最快的,因为它的复杂度与数组的长度成正比。
代码实现
import heapq
def k_smallest_pairs(nums1, nums2, k):
"""
:type nums1: List[int]
:type nums2: List[int]
:type k: int
:rtype: List[List[int]]
"""
# 使用小根堆存储nums1和 nums2 的前 k 个最小的数对。
heap = []
for i in range(min(k, len(nums1))):
for j in range(min(k, len(nums2))):
heapq.heappush(heap, (nums1[i] + nums2[j], i, j))
# 重复以下步骤 k 次。
result = []
while heap and k > 0:
# 从小根堆中弹出最小的数对。
_, i, j = heapq.heappop(heap)
# 将这个数对添加到输出中。
result.append([nums1[i], nums2[j]])
k -= 1
# 如果 i+1 < len(nums1),则将(nums1[i+1], nums2[j])添加到小根堆中。
if i + 1 < len(nums1):
heapq.heappush(heap, (nums1[i+1] + nums2[j], i+1, j))
# 如果 j+1 < len(nums2),则将(nums1[i], nums2[j+1])添加到小根堆中。
if j + 1 < len(nums2):
heapq.heappush(heap, (nums1[i] + nums2[j+1], i, j+1))
return result
def main():
nums1 = [1, 7, 11]
nums2 = [2, 4, 6]
k = 3
result = k_smallest_pairs(nums1, nums2, k)
print(result)
if __name__ == "__main__":
main()
总结
在这篇文章中,我们介绍了如何使用小根堆、多路归并、二分和滑动窗口算法来解决 LeetCode 373 查找和最小的 K 对数字问题。我们还比较了这四种算法的复杂度,并提供了代码实现。