【LeetCode】4.Median of Two Sorted Arrays 兩個排序陣列的中位數
示例 1:
nums1 = [1, 3] nums2 = [2] 中位數是 2.0
示例 2:
nums1 = [1, 2] nums2 = [3, 4] 中位數是 (2 + 3)/2 = 2.5
解題思路:
糟糕- -沒理解題意,首先需要知道“中位數”的含義,其次,題目對時間複雜度做了要求,必須為O(log (m+n))。
先寫理解的程式碼,猜測題意:
nums = sorted(nums1 + nums2) lenth = len(nums) if lenth % 2 == 0: return (nums[lenth//2] + nums[lenth//2 - 1]) / 2 else: return nums[lenth//2]
116 ms,打敗了47.53%的對手。
[沉思],也就是說,我對題目的理解是正確的,本題確實要輸出兩個排序陣列最中間的數。
本題的難點在於排序演算法,
我用Python自帶sorted排序演算法就不對了,我需要找到儘可能快的排序演算法並寫出。
解題思路1:
排序有多種方式,在網上可以輕易搜到。
但本題的重點,是排序兩個有序陣列。
我想,用一個數組挨個往另一個數組裡插是個不錯的選擇。
如圖:
..............畫的什麼鬼圖.................
程式碼:
nums = nums1 + nums2 for i in range(len(nums1), len(nums)): for j in range(i, -1, -1): if nums[i] < nums[j]: nums[i], nums[j] = nums[j], nums[i] i = j # print(nums) lenth = len(nums) if lenth % 2 == 0: return (nums[lenth // 2] + nums[lenth // 2 - 1]) / 2 else: return nums[lenth // 2]
然則............Time Limit Exceeded............
也對....sorted排序是底層語言寫的...我這排序又怎麼能快過它.............
所以,要麼有更快速的排序,要麼,這道題真正的做法不是排序。
解題思路2:
仔細思考一下,這道題並不需要生成排序的陣列- -只是要找到中位數罷了。
lenth = len(nums1) + len(nums2) loc = lenth // 2 - 1 print(loc) i, j, count = 0, 0, 0 while i < len(nums2) and j < len(nums1) and count != loc: if nums2[i] > nums1[j]: j = j + 1 else: i = i + 1 count = j + i if i == len(nums2): median = nums1[lenth // 2 - i] if lenth % 2 == 0: prevMedian = nums1[lenth // 2 - i - 1] elif j == len(nums1): median = nums2[lenth // 2 - j] if lenth % 2 == 0: prevMedian = nums2[lenth // 2 - j - 1] elif count == loc: if nums2[i] > nums1[j]: prevMedian = nums1[j] j = j + 1 else: prevMedian = nums2[i] i = i + 1 if i == len(nums2): median = nums1[lenth // 2 - i] elif j == len(nums1): median = nums2[lenth // 2 - j] elif nums2[i] > nums1[j]: median = nums1[j] j = j + 1 else: median = nums2[i] i = i + 1 # print(i, j, prevMedian, median) if lenth % 2 == 0: return ((prevMedian + median) / 2) else: return median
148 ms,打敗了31.36%的對手。
更重要的是- -我寫的真噁心........
如果說這個演算法有什麼缺點的話,那應該是從中間比較而不是從最初比較。
來看一下官方解題思路..
解題思路3:
這道題官方甚至給了Python程式碼。
而且- -沒有用模除,修改後的程式碼如下:
m, n = len(nums1), len(nums2)
if m > n:
nums1, nums2, m, n = nums2, nums1, n, m
if n == 0:
raise ValueError
imin, imax, half_len = 0, m, (m + n + 1) // 2
while imin <= imax:
i = (imin + imax) // 2
j = half_len - i
if i < m and nums2[j-1] > nums1[i]:
# i is too small, must increase it
imin = i + 1
elif i > 0 and nums1[i-1] > nums2[j]:
# i is too big, must decrease it
imax = i - 1
else:
# i is perfect
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
144ms,打敗了35.78%的對手。
很好,這個故事告訴我們,請消停的排序,不要滿腦子騷操作。
這個演算法與我的找中位數的演算法不同為:
.........就是完全一樣,只是我是從最小開始比,這個演算法是從中間開始比。下次我注意。
解題思路4:
來看一下討論區,有沒有哪位前輩分享程式碼。
...............................沒找到更好的演算法.........................莫非是我英語水平不夠?
前面的53%的使用者到底是怎麼做的?
待我查查其他部落格文章。
這篇文章使用了nums.append(nums1.pop(0))的方法來排序,只花了112ms。
我終於學到了如何檢視更快的演算法,原來是直接點選柱狀圖就可以。