leetcode4 尋找兩個有序陣列的中位數

2021-10-01 20:26:34 字數 2595 閱讀 5289

給定兩個大小為 m 和 n 的有序陣列 nums1 和 nums2。

請你找出這兩個有序陣列的中位數,並且要求演算法的時間複雜度為 o(log(m + n))。

你可以假設 nums1 和 nums2 不會同時為空。

示例 1:

nums1 = [1, 3]

nums2 = [2]

則中位數是 2.0

示例 2:

nums1 = [1, 2]

nums2 = [3, 4]

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

這道題讓我們求兩個有序陣列的中位數,而且限制了時間複雜度為o(log (m+n)),看到這個時間複雜度,自然而然的想到了應該使用二分查詢法來求解。那麼回顧一下中位數的定義,如果某個有序陣列長度是奇數,那麼其中位數就是最中間那個,如果是偶數,那麼就是最中間兩個數字的平均值。這裡對於兩個有序陣列也是一樣的,假設兩個有序陣列的長度分別為m和n,由於兩個陣列長度之和 m+n 的奇偶不確定,因此需要分情況來討論,對於奇數的情況,直接找到最中間的數即可,偶數的話需要求最中間兩個數的平均值。為了簡化**,不分情況討論,我們使用乙個小trick,我們分別找第 (m+n+1) / 2 個,和 (m+n+2) / 2 個,然後求其平均值即可,這對奇偶數均適用。加入 m+n 為奇數的話,那麼其實 (m+n+1) / 2 和 (m+n+2) / 2 的值相等,相當於兩個相同的數字相加再除以2,還是其本身。

這裡我們需要定義乙個函式來在兩個有序陣列中找到第k個元素,下面重點來看如何實現找到第k個元素。首先,為了避免產生新的陣列從而增加時間複雜度,我們使用兩個變數i和j分別來標記陣列nums1和nums2的起始位置。然後來處理一些邊界問題,比如當某乙個陣列的起始位置大於等於其陣列長度時,說明其所有數字均已經被淘汰了,相當於乙個空陣列了,那麼實際上就變成了在另乙個陣列中找數字,直接就可以找出來了。還有就是如果k=1的話,那麼我們只要比較nums1和nums2的起始位置i和j上的數字就可以了。難點就在於一般的情況怎麼處理?因為我們需要在兩個有序陣列中找到第k個元素,為了加快搜尋的速度,我們要使用二分法,對k二分,意思是我們需要分別在nums1和nums2中查詢第k/2個元素,注意這裡由於兩個陣列的長度不定,所以有可能某個陣列沒有第k/2個數字,所以我們需要先檢查一下,陣列中到底存不存在第k/2個數字,如果存在就取出來,否則就賦值上乙個整型最大值。如果某個陣列沒有第k/2個數字,那麼我們就淘汰另乙個數字的前k/2個數字即可。有沒有可能兩個陣列都不存在第k/2個數字呢,這道題裡是不可能的,因為我們的k不是任意給的,而是給的m+n的中間值,所以必定至少會有乙個陣列是存在第k/2個數字的。最後就是二分法的核心啦,比較這兩個陣列的第k/2小的數字midval1和midval2的大小,如果第乙個陣列的第k/2個數字小的話,則說明陣列1中的前k/2個元素不可能成為第k個元素的候選,所以我們可以將其淘汰,將nums1的起始位置向後移動k/2個,並且此時的k也自減去k/2,呼叫遞迴。反之,我們淘汰nums2中的前k/2個數字,並將nums2的起始位置向後移動k/2個,並且此時的k也自減去k/2,呼叫遞迴即可。

class solution(object):

def findmediansortedarrays(self, nums1, nums2):

""":type nums1: list[int]

:type nums2: list[int]

:rtype: float

"""m = len(nums1)

n = len(nums2)

left = (m+n+1)//2

right = (m+n+2)//2

return (self.findkth(nums1,0,nums2,0,left) + self.findkth(nums1,0,nums2,0,right))/2.0

def findkth(self,nums1,i,nums2,j,k):

if i>=len(nums1):

return nums2[j+k-1]

if j>=len(nums2):

return nums1[i+k-1]

if k == 1:

return min(nums1[i],nums2[j])

# 分別找到兩個陣列中第k/2個數是什麼

if i + k//2 -1 < len(nums1):

mid1 = nums1[i + k / 2 - 1]

else:

# 無窮大,如果某個陣列沒有第k/2個數字,那麼我們就淘汰另乙個數字的前k/2個數字即可

mid1 = float("inf")

if j + k//2 -1 < len(nums2):

mid2 = nums2[j + k / 2 - 1]

else:

mid2 = float("inf")

# 比較兩個陣列中第k/2個數的大小關係

if mid1 < mid2:

# 去移動更小的那面的值

return self.findkth(nums1,i+k//2,nums2,j,k-k//2)

else:

return self.findkth(nums1,i,nums2,j+k//2,k-k//2)

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

給定兩個大小為 m 和 n 的有序陣列 nums1 和 nums2。請你找出這兩個有序陣列的中位數,並且要求演算法的時間複雜度為 o log m n 你可以假設 nums1 和 nums2 不會同時為空。示例 1 nums1 1,3 nums2 2 則中位數是 2.0 示例 2 nums1 1,2 ...

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

給定兩個大小為 m 和 n 的有序陣列nums1和nums2。請你找出這兩個有序陣列的中位數,並且要求演算法的時間複雜度為 o log m n 你可以假設nums1和nums2不會同時為空。示例 1 nums1 1,3 nums2 2 則中位數是 2.0示例 2 nums1 1,2 nums2 3,...

LeetCode4 尋找兩個有序陣列的中位數

給定兩個大小為 m 和 n 的有序陣列nums1和nums2。請你找出這兩個有序陣列的中位數,並且要求演算法的時間複雜度為 o log m n 你可以假設nums1和nums2不會同時為空。示例 1 nums1 1,3 nums2 2 則中位數是 2.0示例 2 nums1 1,2 nums2 3,...