LeetCode4. 寻找两个有序数组的中位数

题目描述

寻找两个有序数组的中位数
给定两个大小为 m 和 n 的有序数组 nums1 和 nums2。

请你找出这两个有序数组的中位数,并且要求算法的时间复杂度为 O ( l o g ( m + n ) ) O(log(m + n)) 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

解决方法

方法一:合并,排序,除以2

对于一个有序数组,如果数组长度是奇数,那么中位数就是中间那个值,如果长度是偶数,就是中间两个数的平均数。

class Solution:
    def findMedianSortedArrays(self, nums1, nums2):
        """
        :type nums1: List[int]
        :type nums2: List[int]
        :rtype: float
        """
        tmp = nums1 + nums2
        tmp.sort()
        if len(tmp)%2==1:
            return tmp[int(len(tmp)/2)]
        else:
            return (tmp[int(len(tmp)/2)-1] + tmp[int(len(tmp)/2)])/2.0

Time Complexity: O ( n ) O(n) O(n)
大于题目要求的时间复杂度

方法二:寻找划分位置

中位数的作用:将一个集合划分为两个长度相等的子集,其中一个子集中的元素总是大于另一个子集中的元素。

思路:nums1和nums2分别以i,j为界划分成左右两部分,不断调整i,j,以达成以下条件:

  1. len(nums1_左) + len(nums2_左) = len(nums1_右) + len(nums2_右) 就是说,划分后的左右两边的长度相等。
  2. Max(nums1左、nums2左) ≤ Min(nums1右、nums2右) 就是说,左边的元素总是小于右边。
class Solution:
    def findMedianSortedArrays(self, nums1, nums2):
        """
        :type nums1: List[int]
        :type nums2: List[int]
        :rtype: float
        """
        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太小
                imin = i+1
            elif i>0 and nums1[i-1]>nums2[j]: #i太大
                imax = i-1
            else:#找到i的正确位置
                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

Time Complexity: O ( l o g ( m i n ( m , n ) ) ) O(log(min(m,n))) O(log(min(m,n)))
首先,查找的区间是 [0,m]。 而该区间的长度在每次循环之后都会减少为原来的一半。 所以,我们只需要执行 \log(m) 次循环。由于我们在每次循环中进行常量次数的操作,所以时间复杂度为 O ( l o g ( m ) ) O(log(m)) O(log(m))。 由于 m ≤ n m\leq n mn,所以时间复杂度是 O ( log ⁡ ( min ⁡ ( m , n ) ) ) O(\log(\min(m,n))) O(log(min(m,n)))
空间复杂度: O ( 1 ) O(1) O(1), 我们只需要恒定的内存来存储 9 个局部变量, 所以空间复杂度为 O ( 1 ) O(1) O(1)

参考

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值