LeetCode 刷题之旅(2020.05.24)——4. 寻找两个正序数组的中位数(难)

LeetCode 刷题之旅(2020.05.24)——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, 4]

则中位数是 (2 + 3)/2 = 2.5

解题模板:
Python 3:

class Solution:
    def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:
        

解题思路:

  • Python偷懒法:

众所周知,List.sort()函数可以实现排序,只不过时间复杂度为 O( (N + M) * log(N + M) ),通过位序直接返回结果。

  • 双指针比较法:

基本方法:类似两列表有序合并的实现算法,对比两指针所指元素,数值小的指针后移,到达相应次数停止,返回结果。

  • 分治法:

中间点的位置就在(len1 + len2 + 1) // 2
考虑一般情况下,第一个序列存在一个数,其左边都是小于中位数,右边都大于;第二个序列也是一样。这两个数的序列分别在 mid1 和 mid2。如果 mid2 左侧的数比 mid1 对应的数都大,那么第一行的中间靠左;如果 mid2 左侧的数比 mid1 大,那么选第二行的小的和第一行大的数,这样的数更接近。把第一行的中间往右,即二分查找的更新 left,反之更新 right。

解法:

  • Python偷懒法:
class Solution:
    def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:
        result = nums1 + nums2
        result.sort()
        if len(result) % 2 != 0:
            return result[len(result) // 2]
        else:
            right = len(result) // 2
            left = right - 1
            return (result[left] + result[right]) / 2

时间复杂度O( (N + M) * log(N + M) )
空间复杂度O(N + M)

  • 双指针比较法:
class Solution:
    def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:
        length = len(nums1) + len(nums2)
        if length % 2 == 0:
            mid = length // 2 - 1
            a, b = 0, 0
            for i in range(mid):
                if a in range(len(nums1)) and b in range(len(nums2)):
                    if nums1[a] <= nums2[b]:
                        a += 1
                    else:
                        b += 1
                elif a in range(len(nums1)):
                    a += 1
                else:
                    b += 1
            if a in range(len(nums1)) and b in range(len(nums2)):
                if nums1[a] <= nums2[b]:
                    if a + 1 in range(len(nums1)):
                        if nums1[a+1] <= nums2[b]:
                            return (nums1[a] + nums1[a+1]) / 2
                    return (nums1[a] + nums2[b]) / 2
                else:
                    if b + 1 in range(len(nums2)):
                        if nums2[b + 1] <= nums1[a]:
                            return (nums2[b] + nums2[b + 1]) / 2
                    return (nums2[b] + nums1[a]) / 2
            elif a in range(len(nums1)):
                return (nums1[a] + nums1[a+1]) / 2
            else:
                return (nums2[b] + nums2[b+1]) / 2
        else:
            mid = length // 2
            a, b = 0, 0
            for i in range(mid):
                if a in range(len(nums1)) and b in range(len(nums2)):
                    if nums1[a] <= nums2[b]:
                        a += 1
                    else:
                        b += 1
                elif a in range(len(nums1)):
                    a += 1
                else:
                    b += 1
            if a in range(len(nums1)) and b in range(len(nums2)):
                return nums1[a] if nums1[a] <= nums2[b] else nums2[b]
            elif a in range(len(nums1)):
                return nums1[a]
            else:
                return nums2[b]

时间复杂度O(N + M)
空间复杂度O(1)

  • 分治法:
class Solution:
    def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:
        len_1, len_2 = len(nums1), len(nums2)
        if len_1 > len_2:
            nums1, nums2, len_1, len_2 = nums2, nums1, len_2, len_1
        min_, max_, mid_ = 0, len_1, (len_1 + len_2 + 1) / 2
        while min_ <= max_:
            i = (min_ + max_) // 2
            j = int(mid_ - i)
            if i < len_1 and nums2[j-1] > nums1[i]:
                min_ = i + 1
            elif i > 0 and nums1[i-1] > nums2[j]:
                max_ = i - 1
            else:
                if i == 0:
                    left = nums2[j-1]
                elif j == 0:
                    left = nums1[i-1]
                else:
                    left = max(nums1[i-1], nums2[j-1])
                if (len_1 + len_2) % 2 == 1:
                    return left
                if i == len_1:
                    right = nums2[j]
                elif j == len_2:
                    right = nums1[i]
                else:
                    right = min(nums1[i], nums2[j])
                return (left + right) / 2.0

时间复杂度O( log(N + M) )
空间复杂度O(1)

你可能感兴趣的:(LeetCode每日一题,LeetCode难题)