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)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值