題目來源: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
k
個最小數。若爲奇數,則第 k
位所在的數就是中位數;若爲偶數,則第 k
小的數與第 k + 1
小的數之和的一半就是中位數;k
小的數,不需逐個比較,一個個剔除。能夠考慮一半一半的排除,每次排除 k/2
個數字。k/2
位數(當 k
爲奇數時,向下取整),當出現其中一個數組的值較小時,說明這個數組包括第 k/2
位數以及前面的數字都比第 k
位數小,直接剔除;此時 k
也要減去剔除數字的個數,遞歸執行這個步驟;k
爲 1
的時候;k
爲 1
的時候,這時求第 1
小的數,只要比較兩個數組首位數字較小便是所求的中位數;k
不等於 1
時,這個時候,取其中不爲空數組的第 k
小的數。例子 1:spa
nums1: [1, 3, 5] nums2: [1, 2, 3, 4, 5, 6, 7, 8]
這個例子中,假設要求的是第 6
小的數字。比較 k/2
也就是第 3 個數。code
nums1 第 3 個數字爲 5
,nums2 第 3 個數字爲 3
,5 > 3
,因此將下面數組的 3 個數字剔除掉,變成比較 [1, 3, 5]
與 [4, 5, 6, 7, 8]
,這個時候剔除 3
個數字,因此 k 需減去 3,此時 k=3
。繼續比較;blog
k/2
不能整除,向下取整,爲 1
,比較兩個數組第一個數字,此時 1<4
,剔除第一個數組的 1
,剩下 [3, 5]
和 [4, 5, 6, 7, 8]
,k
爲 3-1=2
,再次比較;遞歸
k/2
爲 1
,3<4
,剔除第一個數組的 3
,剩下 [5]
和 [4, 5, 6, 7, 8]
,k
爲 2-1=1
。
此時 k=1
,也就是求第 1 小的數字,這個時候比較剩下兩個數組的首位數字,去較小的數字即爲第 1 小的數字,也就是 4
。
例子 2:
這裏考慮數組長度小於 k/2
的狀況:
nums1: [1, 2] nums2: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
一樣求第 6
小的數。
解題思路如 例子 1,先比較第 k/2
位數的大小,k/2=3
。因爲第一個數組長度小於 3,這時直接取最末尾的數字 2
,而第二個數組取第 3 位數,也就是 3
,這裏 2<3
,直接剔除第一個數組的兩個數字,k 則變爲 6-2=4
。
因爲此時第一個數組爲空,因此這個時候直接取另一個數組第 k
小,也就是第 4
小數,也就是 4
,便是原本要求的兩個數組中第 6
小的數字。
由於每次循環都會減小 k/2
個元素,因此時間複雜度是O(log(k))
,而 k
在本題中就是 (m+n)/2
,因此最終複雜度就是 O(log(m+n))
。
class Solution: def findMedianSortedArrays(self, nums1, nums2) -> float: m = len(nums1) n = len(nums2) # 這裏默認爲偶數狀況,若爲奇數,則計算兩次相同的 k 值 med_left = (m + n + 1) // 2 med_right = (m + n + 2) // 2 return (get_k_num(nums1, 0, m-1, nums2, 0, n-1, med_left) + get_k_num(nums1, 0, m-1, nums2, 0, n-1, med_right)) / 2 def get_k_num(nums1, head1, end1, nums2, head2, end2, k): len1 = end1 - head1 + 1 len2 = end2 - head2 + 1 # 遞歸跳出條件 if (len1 == 0): return nums2[head2 + k - 1] if (len2 == 0): return nums1[head1 + k - 1] if (k == 1): return min(nums1[head1], nums2[head2]) i = head1 + min(len1, k // 2) - 1 j = head2 + min(len2, k // 2) - 1 if (nums1[i] > nums2[j]): return get_k_num(nums1, head1, end1, nums2, j + 1, end2, k - (j - head2 + 1)) else: return get_k_num(nums1, i + 1, end1, nums2, head2, end2, k - (i - head1 + 1))
以上就是本篇的主要內容。
吐槽: 本篇幅解題思路寫下來,回頭看的時候,發現純文字感受邏輯會有點亂,下次爭取結合圖例完善這部分的內容。
歡迎關注微信公衆號《書所集錄》