4. 寻找两个有序数组的中位数
给定两个大小为 m 和 n 的有序数组 nums1 和 nums2。
请你找出这两个有序数组的中位数,并且要求算法的时间复杂度为 O(log(m + n))。
你可以假设 nums1 和 nums2 不会同时为空。
示例 1:
nums1 = [1, 3] nums2 = [2]
则中位数是 2.0
示例 2:
nums1 = [1, 2] nums2 = [3, 4]
则中位数是 (2 + 3)/2 = 2.5
来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/median-of-two-sorted-arrays
看到时间复杂度为 O(log(m+n)),理所当然的想到,小根堆(大根堆)
因为构建根堆的时间复杂度就是 log(N)。
当然,如果没有这个条件限制,那么会产生以下的思考。
姿势 1
直接整合排序找中位数:
class Solution:
def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:
nums1 = nums1 + nums2
nums1.sort()
length = len(nums1)
if length % 2 == 0:
k1 = nums1[int(length / 2) - 1]
k2 = nums1[int(length / 2)]
return (k1 + k2) / 2
else:
return nums1[int(length / 2)]
简单粗暴,但是时间复杂度肯定不符合要求,虽然跑测试通过了。
可能在调用自带的 sort 方法的时候会自动做优化,但是肯定也不符合要求。
sort 与 sorted 区别:
sort 是应用在 list 上的方法,sorted 可以对所有可迭代的对象进行排序操作。
list 的 sort 方法返回的是对已经存在的列表进行操作,无返回值,而内建函数 sorted 方法返回的是一个新的 list,而不是在原来的基础上进行的操作。
姿势 2
再就想到的是将两个列表整合起来排序,由于是两个有序数组,可以使用链表的合并。
优化一点就是,合并到中位数就停止。
有序链表的合并属于数据结构基础知识,不再赘述。
时间复杂度肯定不达标,大概是 O(N)
姿势 3
正主,小根堆。
借助的是 heapq 实现小根堆。
这个肯定是符合时间复杂度要求的,但是这个效率和内存不太满意。
import heapq
class TopkHeap(object):
def __init__(self, k):
self.k = k
self.data = []
def push(self, elem):
if len(self.data) < self.k:
heapq.heappush(self.data, elem)
else:
topk_small = self.data[0]
if elem > topk_small:
heapq.heapreplace(self.data, elem)
def TopK(self):
return [x for x in reversed([heapq.heappop(self.data) for x in range(len(self.data))])]
class Solution:
def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:
len1 = len(nums1)
len2 = len(nums2)
nums = nums1+nums2
# 如果即奇数个,则直接取中位数,也就是第k大的值
if (len1+len2) % 2 != 0:
k = int((len1+len2)/2+1)
th = TopkHeap(k)
for i in nums:
th.push(i)
return th.TopK()[-1]
# 如果是偶数个
else:
k = int((len1+len2)/2+1)
th = TopkHeap(k)
for i in nums:
th.push(i)
data = th.TopK()
return (data[-1]+data[-2])/2
姿势 4
官方说的,二分法?没怎么看懂。感觉还是比较复杂的。
https://leetcode-cn.com/problems/median-of-two-sorted-arrays/solution/4-xun-zhao-liang-ge-you-xu-shu-zu-de-zhong-wei-shu/
这个回答挺好的。但是我没法复述了。。。