leetcode高频题 4.Median of Two Sorted Arrays-两个有序数组的中位数

leetcode 4.Median of Two Sorted Arrays-两个有序数组的中位数

题目

题目链接

思路

  1. 合并,取中位数
    归并排序思想合并至中位数位置

  2. 切分法
    转变为在两个有序数组中寻找第k小的数
    L奇数时,令k=L/2,结果为f(k+1)
    L偶数时,结果为(f(k) + f(k+1))/2
    L=len(nums1) + len(nums2)

取nums1的前k1,nums2的前k2个,k1+k2=k,判断最后一位的大小,如果相等,则就是中位数
如果不相等,虽然无法肯定这两个是否是中位数,则可以把问题规模缩小
nums1 = [a0,a1,a2,a3,a4]
nums2 = [b0, b1, b2, b3]

取k=5,k1=3,k2=2
举例
a2<b1
nums1 = [1,2,3,5,6], nums2=[4,7,8,9]
即取[1,2,3]和[4,7],可以将[1,2,3]排除,因为k1<k,不会在这k1个中 (排除前半部分)
将[8,9]排除,因为3<7,即目前取的k个中7是最大值,所以第k大不会超过7 (排除后半部分)

a2>b1
nums1 = [5,6,7,8,9], nums2=[1,2,3,4]
即取[5,6,7]和[1,2],可以将[1,2]排除,因为k2<k,不会在这k1个中 (排除前半部分)
将[8,9]排除,因为2<7,即目前取的k个中7是最大值,所以第k大不会超过7 (排除后半部分)

即nums1和nums2的最后一个元素小的必定被排除,最后一个元素大的后面的元素必定被排除

合并法复杂度

  • 时间复杂度
    两个数组从前到后只遍历一次,

    O

    (

    n

    )

    \mathcal{O}(n)

    O(n)

  • 空间复杂度
    两个数组从前到后只遍历一次,

    O

    (

    n

    )

    \mathcal{O}(n)

    O(n)

切分法复杂度

  • 时间复杂度
    求中位数,

    k

    =

    (

    m

    +

    n

    )

    2

    ,

    k

    1

    =

    k

    2

    ,

    k

    2

    =

    k

    2

    k=\frac{(m+n)}{2}, k_1=\frac{k}{2}, k_2=\frac{k}{2}

    k=2(m+n),k1=2k,k2=2k,每次规模减半
    类似二分搜索,为

    O

    (

    l

    o

    g

    (

    (

    m

    +

    n

    )

    2

    )

    )

    O(log(\frac{(m+n)}{2}))

    O(log(2(m+n)))

  • 空间复杂度
    递归时传递的nums数组不会复制,只使用了常数个变量,

    O

    (

    1

    )

    \mathcal{O}(1)

    O(1)

合并,取中位数代码

class Solution:
    def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:
        total_length = len(nums1) + len(nums2)
        is_odd = total_length % 2
        split_location = int(total_length / 2) + 1
        i = j = 0
        merged_array = list()
        while len(merged_array) < split_location:  # 个数不够继续循环
            if i < len(nums1):  # nums1没有取完
                if j < len(nums2):  # nums1没有取完的情况下,nums2也没有取完,判断应该从哪个列表取
                    if nums1[i] <= nums2[j]:
                        merged_array.append(nums1[i])
                        i += 1
                    else:
                        merged_array.append(nums2[j])
                        j += 1
                else:  # nums1没有取完,nums2取完了,只在nums1中取
                    merged_array.append(nums1[i])
                    i += 1
            else:  # nums1取完了,则在nums2中取
                if j < len(nums2):
                    merged_array.append(nums2[j])
                    j += 1
                else:
                    break
        # 中位数计算
        return merged_array[-1] if is_odd else (merged_array[-1] + merged_array[-2]) / 2

切分法代码

class Solution:
    def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:
        m = len(nums1)
        n = len(nums2)
        k = int((m + n) / 2)

        if (m + n) % 2 == 1:  # 总长度为奇数,返回第k大的值
            return self.find_k_th(nums1, 0, m - 1, nums2, 0, n - 1, k + 1)
        else:  # 总长度为偶数,返回第k大和第k+1大两个数的平均值
            return (self.find_k_th(nums1, 0, m - 1, nums2, 0, n - 1, k)
                    + self.find_k_th(nums1, 0, m - 1, nums2, 0, n - 1, k + 1)) / 2.0

    def find_k_th(self, nums1, l1, h1, nums2, l2, h2, k):
        # 寻找第k小的元素
        # 取nums1的[l1, h1]区间和nums2的[l2,h2]区间进行判断
        m = h1 - l1 + 1
        n = h2 - l2 + 1
        if m > n:  # m>n,将nums1和nums2互换,加快程序运行
            return self.find_k_th(nums2, l2, h2, nums1, l1, h1, k)
        if m == 0:  # nums1长度为0,返回nums2第k小的数
            return nums2[l2 + k - 1]

        if k == 1:  # k=1时,取最小值,即两个数组最左侧值
            return min(nums1[l1], nums2[l2])
        
        # 分别选两个数组的中间数
        na = min(int(k / 2), m)
        nb = k - na
        va = nums1[l1 + na - 1]
        vb = nums2[l2 + nb - 1]
        if va == vb:  # 相等就是中位数
            return va
        elif va < vb:  # 不相等,剪枝,nums1的前na个数和nums2 nb后的数全部排除
            return self.find_k_th(nums1, l1 + na, h1, nums2, l2, l2 + nb - 1, k - na)
        else:  # 不相等,剪枝,nums1 na后的数和nums2 前nb个数全部排除
            return self.find_k_th(nums1, l1, l1 + na - 1, nums2, l2 + nb, h2, k - nb)

版权声明:本文为qq_17065591原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。