LeetCode4:Median of Two Sorted Arrays
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:連結
第一種方法:設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))
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+1]) elif a[a_mid-1] > b[b_mid-1]: return find_k_th(k-b_mid, a[:a_mid+1], 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)&1: 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