1.题目
给定两个大小为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的中位数。
进阶:你能设计一个时间复杂度为 O(log (m+n)) 的算法解决此问题吗?
输入:nums1 = [1,3], nums2 = [2]
输出:2.00000
解释:合并数组 = [1,2,3] ,中位数 2
2.代码
分析:
# m+n偶数: ((m+n)/2 + (m+n)/2 +1)/2,奇数: (m+n)/2+1
# ==>找出第(m+n)/2或(m+n)/2+1小的数 ==>找出第k小数
1).二分法 O(log(m+n)):
# 二分法:O(log(m+n))
"""
A[0,...,m],B[0,...,n]
C[0,...,k,...,m+n]
找C[k]即第k小数思路:
A[0,...,k//2-1,...,m]
B[0,...,k//2-1,...,n]
| k//2 |
min(A[k//2-1],B[k//2-1])
最少大于k//2-1个数,即[0,...,k//2-2];
最多大于(k//2-1)*2 = k-2个数,即[0,...,k//2-2)]*2,若A[k//2-1]==B[k//2-1]也是最多大于k-2个数
⇒ min(A[k//2-1],B[k//2-1])顶多是第k-1小数 ⇒ 不是第k个数且在k左边 ⇒ 那[0,k//2-2]肯定也在k左边
⇒ [0,...,k//2-1]可以舍掉
⇒ 找[k//2,...,m] 中第(k-((k//2-1) -0 +1))小的数
[0,...,k//2-1,...,n]
"""
class Solution:
def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:
# 使用index_1 ,index_2实现对list的切割,因为只能从前面开始切。
# newIndex_1/2 是要比较的数,小的话使index = newIndex+1 实现切割
def findKmin(k):
index_1, index_2 = 0, 0
while 1:
if index_1 == m:
return B[index_2 + k -1]
if index_2 == n:
return A[index_1 + k -1]
if k == 1:
return min(A[index_1], B[index_2])
newIndex_1 = min(index_1+k//2-1,m-1)
newIndex_2 = min(index_2+k//2-1,n-1)
if A[newIndex_1]<=B[newIndex_2]:
k = k - (newIndex_1 - index_1 +1)
index_1 = newIndex_1 + 1
else:
k = k - (newIndex_2 - index_2 +1)
index_2 = newIndex_2 + 1
A,B = nums1, nums2
m, n = len(A), len(B)
totalLength = m + n
if totalLength % 2 == 1:
return findKmin(totalLength//2+1)
else:
return (findKmin(totalLength//2) + findKmin(totalLength//2+1))/2
2). 排序 O(nlog(k+n)):
#sort: O(nlog(k+n))
class Solution:
def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:
nums1.extend(nums2)#O(n)
num = sorted(nums1)#O(nlog(m+n))
#O(1)
if len(num) % 2 == 1:
return num[(len(num)-1)//2]
else:
return (num[len(num)//2-1]+num[len(num)//2])/2