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
執行結果