1. 程式人生 > >LeetCode4:Median of Two Sorted Arrays

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