1. 程式人生 > 其它 >LeetCode-4 尋找兩個正序陣列的中位數

LeetCode-4 尋找兩個正序陣列的中位數

題目來源:力扣(LeetCode)
連結:https://leetcode-cn.com/problems/median-of-two-sorted-arrays/

題目描述

給定兩個大小分別為 m 和 n 的正序(從小到大)陣列nums1 和nums2。請你找出並返回這兩個正序陣列的 中位數 。

演算法的時間複雜度應該為 O(log (m+n)) 。

示例 1:

輸入:nums1 = [1,3], nums2 = [2]
輸出:2.00000
解釋:合併陣列 = [1,2,3] ,中位數 2


示例 2:

輸入:nums1 = [1,2], nums2 = [3,4]
輸出:2.50000
解釋:合併陣列 = [1,2,3,4] ,中位數 (2 + 3) / 2 = 2.5


示例 3:

輸入:nums1 = [0,0], nums2 = [0,0]
輸出:0.00000


示例 4:

輸入:nums1 = [], nums2 = [1]
輸出:1.00000


示例 5:

輸入:nums1 = [2], nums2 = []
輸出:2.00000

提示:

nums1.length == m
nums2.length == n
0 <= m <= 1000
0 <= n <= 1000
1 <= m + n <= 2000
-106 <= nums1[i], nums2[i] <= 106

解題思路

單從題幹來說,這就是一道歸併排序題,最初的想法是將兩個vector數量求和除以二得到n,然後歸併排序找出第n個數來,不出所料,時間超出限制。

困難題果然不簡單,關鍵是“演算法的時間複雜度應該為 O(log (m+n)) ”,如果使用歸併排序的方法,那麼時間複雜度必然是O(m+n),還是太久了。

這個時候其實理所當然應該想到二分法,不過還有另一種解法也十分的有趣。

假設兩個陣列分別為A,B,陣列程度分別為m,n:

中位數的意義就是將一個數組平均的分成兩個部分,這兩個部分有相同數目的元素,對於未合併的兩個陣列來說也一樣,假設我們將A陣列在第i個地方分開,B陣列在第j個地方分開,那麼A[i]或者B[j]是中位數的必須滿足的條件就是:

1、i + j = m - i + n - j(m+n為偶數時)或者i + j = m - i + n - j + 1(m + n為奇數)。

2、A[i - 1] <= B[j] 並且 B[j - 1] <= A[i].

通過條件1,在確定i的情況下可以確定j的值,那麼我們需要使用二分法找到一個i滿足條件2便可以找到中位數。

在確定i之後,比較A中第i個數和B中第j個數,如果m+n是奇數,那麼A中第i個數和B中第j個數中最大的那個就是中位數,如果m+n是偶數,那麼還需要找到劃分出來的後陣列中最小值,即A中第i+1個數和B中第j+1個數中最大的那個,將前陣列的最大值與後陣列的最小值求均值,就是中位數了。

原始碼展示

class Solution:
    def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:
        m=min(len(nums1),len(nums2))
        n=max(len(nums1),len(nums2))
        A=nums1 if len(nums1)<len(nums2) else nums2
        B=nums2 if len(nums2)>len(nums1) else nums1
        imin=0
        imax=m

        while imin<=imax:
            i=int((imin+imax)/2)
            j=int((m+n+1)/2-i)
            if  i<imax and B[j-1]>A[i]:
                imin=i+1
            elif  i>imin and A[i-1]>B[j]:
                imax=i-1
            else:
                leftx=0
                if i==0 : leftx=B[j-1]
                elif j==0 : leftx=A[i-1]
                else:
                    leftx=max(A[i-1],B[j-1])
                if (m+n)%2==1: return  leftx
                rightx=0
                if i==m :rightx=B[j]
                elif j==n :rightx=A[i]
                else:
                    rightx=min(A[i],B[j])
                return (leftx+rightx)/2.0

執行結果