There are two sorted arrays nums1 and nums2 of size m and n respectively.
Find the median of the two sorted arrays. The overall run time complexity should be O(log (m+n)).
You may assume nums1 and nums2 cannot be both empty.
Example 1:
nums1 = [1, 3]
nums2 = [2]
The median is 2.0
Example 2:
nums1 = [1, 2]
nums2 = [3, 4]
The median is (2 + 3)/2 = 2.5
LeetCode:链接
要求在O(log (m+n))时间内找到中位数,所以像那些合并之后再二分查找、或者一边比较一边合并到总量一半的方法肯定是不行的。
二分法:设num1的长度为m,nums2的长度为n,将问题转化为在两个排好序的数组中找第k=(m+n+1)/2的元素(若总数是偶数还需要找第K+1大的元素)
为了方便说明,假设 m<=n。
每次a_m= min(m, k/2),b_mid = k – a_m,然后比较A中第a_m个元素和B中第b_m个元素,即A[a_m – 1]和B[b_m – 1]:
-
若A[a_m – 1] < B[b_m – 1],则说明第k小的元素不可能出现在A中的前a_m个,也不可能出现在B中的b_m之后。即在A[a_m:],B[:b_m + 1]中查找第k – a_m元素。(因为a_m + b_m = k,不可能出现在A的a_m个的话,B中的前b_m个元素已经足够k-a_m个了);
-
若A[a_m – 1] >B[b_m – 1],则说明第k小的元素不可能出现在B中的前b_m个,也不会再A中的a_m之后,因此,在A[a_m + 1],B[b_m:]中查找k – b_m元素;
-
若相等,则找到了。
复杂度O(log(m + n))
必须先判断find_k_th函数中m和n的大小关系!!!
class Solution(object):
def findMedianSortedArrays(self, nums1, nums2):
"""
:type nums1: List[int]
:type nums2: List[int]
:rtype: float
"""
def find_k_th(k, a, b):
m, n = len(a), len(b)
if m > n:
return find_k_th(k, b, a)
if m == 0:
return b[k-1]
if n == 0:
return a[k-1]
if k == 1:
return min(a[0], b[0])
a_mid = min(k//2, m)
b_mid = k - a_mid
if a[a_mid-1] < b[b_mid-1]:
return find_k_th(k-a_mid, a[a_mid:], b[:b_mid])
elif a[a_mid-1] > b[b_mid-1]:
return find_k_th(k-b_mid, a[:a_mid], b[b_mid:])
else:
return a[a_mid-1]
m, n = len(nums1), len(nums2)
k = (m + n + 1) // 2
ans = find_k_th(k, nums1, nums2)
if (m+n) & 0x1:
return ans
else:
ans = ans + find_k_th(k+1, nums1, nums2)
return ans / 2.0
同样假设m <= n,我们需要找到的是一个i和一个j,这两个下标分别将两个数组划分为左右两部分:
1 2 3 | left_part | right_part A[0], A[1], ..., A[i-1] | A[i], A[i+1], ..., A[m-1] B[0], B[1], ..., B[j-1] | B[j], B[j+1], ..., B[n-1] |
当然i未必和j相等。若能找到一个这样的i和j,满足:
- i + j = (m + n + 1) / 2
- 并且a[i-1] < a[j], b[j-1] < b[i]
这两个条件使得a[i – 1], 和b[j – 1]恰好为在中间的数,谁大谁就是中位数,若m + n为,偶数,则还要考虑a[i]和a[j]中较小的数。(i=0或j=0或i = m或j = n的特殊情况之后讨论)
因此,可以二分枚举i,起始范围left= 0, right = m,则j = (m + n + 1) / 2 – i,
- 若a[i] < b[j – 1],则说明i太小,要增大i,left = i + 1
- 若a[i – 1] > b[j],说明i太大,要减小i,right = i – 1
- 否则找到了i和j的正确位置,看m + n是奇数的话直接返回max(a[i – 1], b [j- 1])即可,否则为(max(a[i – 1], b [j- 1]) + min(a[i], b[j])) / 2
现在讨论边界情况:
- i = 0时,此时j = (m + n + 1) / 2,此时即可假设a[i-1]必定小于b[j],只需要看 a[i] > b[j -1]即可
- i = m时,此时j = (n – m + 1) / 2 > 0,也可以说a[i] > b[j – 1],只需要看a[i – 1] < b[j]即可
- j = 0和j = n同理
class Solution(object):
def findMedianSortedArrays(self, nums1, nums2):
"""
:type nums1: List[int]
:type nums2: List[int]
:rtype: float
"""
m , n = len(nums1), len(nums2)
if m > n:
nums1, nums2, m , n = nums2, nums1, n, m
imin, imax, half_len = 0, m, (m+n+1)//2
while imin <= imax:
i = (imin + imax) // 2
j = half_len - i
if i < m and nums1[i] < nums2[j-1]:
imin += 1
elif i > 0 and nums1[i-1] > nums2[j]:
imax -= 1
else:
if i == 0: max_of_left = nums2[j-1]
elif j == 0: max_of_left = nums1[i-1]
else: max_of_left = max(nums1[i-1], nums2[j-1])
if (m + n) & 1:
return max_of_left
if i == m: min_of_right = nums2[j]
elif j == n: min_of_right = nums1[i]
else: min_of_right = min(nums1[i], nums2[j])
return (max_of_left + min_of_right) / 2.0