LeetCode 尋找兩個有序數組的中位數 | 解二

尋找兩個有序數組的中位數


題目來源:https://leetcode-cn.com/problems/median-of-two-sorted-arrays/submissions/python

題目


給定兩個大小爲 m 和 n 的有序數組 nums1 和 nums2。算法

請你找出這兩個有序數組的中位數,而且要求算法的時間複雜度爲 O(log(m + n))。segmentfault

你能夠假設 nums1 和 nums2 不會同時爲空。數組

示例 1:bash

nums1 = [1, 3]
nums2 = [2]

則中位數是 2.0

示例 2:微信

nums1 = [1, 2]
nums2 = [3, 4]

則中位數是 (2 + 3)/2 = 2.5

解題思路


這裏先理解中位數的概念:在統計學中,中位數指的是可將數值集合劃分爲相等的上下兩部分,其中一部分的元素總大於另外一部分的元素。spa

根據這個概念,咱們如今對兩個數組進行劃分,num1 數組用大寫 A 表示,num2 數組用大寫 B。這裏僅爲方便書寫。code

先對 A 進行劃分,在任意 i 處,將 A 劃分爲兩部分:blog

在任意 j 處,也對 B 進行劃分:leetcode

將 A 跟 B 兩個數組的左邊部分和右邊部分,各合在一塊

按照中位數的概念,只要保證左邊部分與右邊部分的長度相等,且左邊部分的最大數小於右邊部分的最小數,那麼就能夠求出中位數,即:
im1.jpg
要知足上的兩個式子,必須知足下面的條件:
im2.jpg
只要知足上面的等式就可以找到中位數。

第一個條件中,因爲 m + n 和的奇偶不定,分開分析:

im3.jpg

由於 j 的取值爲整數,最終都會向下取整。可是這裏要注意,由於 j 的取值是不能爲負的。因此必須知足 m <= n 的前提,不然 j 有可能小於 0,這樣程序運行起來則會出錯。

im4.jpg
這種狀況,即表示 i 的值太大,須要減少 i 的值,同時增大 j 的值。

上面是不考慮邊界的問題,下面講一下考慮邊界的狀況:

先考慮 i = 0,或者 j = 0,也就是在數組最前面劃分。這個時候,左邊部分當 j = 0 時,左邊最大值則是 A[i-1];當 i = 0 時,最大值就是 B[j-1]。

image

當 i = m 或者 j = n 的狀況下,也就是數組在最後面劃分。當 i = m 時,右邊最小值就是 B[j],當 j = n 時,右邊最小值就是 A[i]

image

上面就是考慮 i 爲 0 或者爲 m 的狀況。j 爲 0 或者 n 的狀況。這裏 i 在變化的時候,j 是否會越出邊界的問題,這個能夠不考慮,以下推導:
im5.jpg

代碼實現


class Solution:
    def findMedianSortedArrays(self, nums1, nums2) -> float:
        m = len(nums1)
        n = len(nums2)
        # 這裏要始終知足 m <= n 的條件,防止運行出錯
        if m > n:
            nums1, nums2, m, n = nums2, nums1, n, m
        # 這裏考慮的兩個數組爲空的狀態,直接拋出異常
        if n == 0:
            raise ValueError

        # 只考慮 i 的取值,j 會隨之變化,且不會越界
        i_min, i_max, half_len = 0, m, (m + n + 1) // 2
        while i_min <= i_max:
            i = (i_min + i_max) // 2
            j = half_len - i
            if i < m and nums2[j-1] > nums1[i]:
                # i 數值太小,增大 i
                i_min = i + 1
            elif i > 0 and nums1[i-1] > nums2[j]:
                # i 數值過大,縮減 i
                i_max = i - 1
            else:
                # 當 i 就是須要找的值時,
                # 考慮邊界在最前面切分時,左邊最大值的取值狀況
                # 以及正常狀況下,左邊最大值的取值狀況
                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) % 2 == 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

實現效果


find_median_result_2.jpg


以上就是《尋找兩個有序數組的中位數》第二種解法,根據中位數的概念。

歡迎關注微信公衆號《書所集錄》
相關文章
相關標籤/搜索