1. 程式人生 > >【LeetCode】4.Median of Two Sorted Arrays 兩個排序陣列的中位數

【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。
我終於學到了如何檢視更快的演算法,原來是直接點選柱狀圖就可以。