LeetCode(4)-Python-寻找两个有序数组的中位数(median-of-two-sorted-arrays)

题目描述

给定两个大小为 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

解决思路1

题目给定的输入是两个list类型,python中的list类型中有一个list.extend()方法,时间复杂度是O(n),可以将两个list类型的列表合并成一个列表,然后对这个新列表进行排序,时间复杂度是O((m+n)log(m+n)),便可以找到中位数了

class Solution:
    def findMedianSortedArrays(self, nums1, nums2):
        """
        :type nums1: List[int]
        :type nums2: List[int]
        :rtype: float
        """
        nums1.extend(nums2)  //时间复杂度O(n)
        nums1.sort()  //时间复杂度O((m+n)log(m+n))
        
        n = len(nums1)
        
        if n%2 == 1:
            return float(nums1[n//2])
        else:
            return (nums1[n//2-1]+nums1[n//2])/2.0

结果 104ms

解决思路2

我们可以将两个数组按序排列成一个数组,然后直接取其中位数,时间复杂度O(m+n)

class Solution:
    def getmid(self,nums):  //处理某个数组为空时的情况
        if len(nums)%2 ==0:
            return (nums[len(nums)//2]+nums[(len(nums)//2)-1])/2
        else:
            return nums[len(nums)//2]
        
    def findMedianSortedArrays(self, nums1, nums2):
        """
        :type nums1: List[int]
        :type nums2: List[int]
        :rtype: float
        """
        if len(nums1)==0:
            return self.getmid(nums2)
        if len(nums2)==0:
            return self.getmid(nums1)
        
        nlen=len(nums1)+len(nums2)
        i=j=0 
        temp=[]
        while (i<len(nums1) and j<len(nums2)):  //为每个数组设立一个指针,将其合并
            if nums1[i]<nums2[j]:
                temp.append(nums1[i])
                i+=1
            else:
                temp.append(nums2[j])
                j+=1
        while (i<len(nums1)):
            temp.append(nums1[i])
            i+=1
        while (j<len(nums2)):
            temp.append(nums2[j])
            j+=1
            
        if nlen%2==0:
            return (temp[nlen//2]+temp[nlen//2-1])/2
        else:
            return temp[nlen//2]
        

结果 88ms

解决思路3

题目中给出了要求的时间复杂度为O(log(m+n)),我们这里想到的是二分查找,二分查找的时间复杂度为O(logn),首先我们先分析下题目,假设两个有序数组共有n个元素,当n为奇数时,查找第(n//2)个元素,当n为偶数时,查找第(n//2)和第(n//2-1)个元素,然后取他们的均值。
考虑二分查找时的情况,我们希望找到第一个数组中前p个元素和第二个数组中前q个元素,我们想要的最终结果是:p+q等于k-1,这样第p+1个元素或者第q+1个元素就是我们要找的第k个元素。
通过二分法将问题规模缩小,假设p=k//2-1,则q=k-p-1,且p+q=k-1。如果第一个数组第p个元素小于第二个数组第q个元素,我们不确定二数组第q个元素是大了还是小了,但一数组的前p个元素肯定都小于目标,所以我们将第一个数组前p个元素全部抛弃,形成一个较短的新数组。然后,用新数组替代原先的第一个数组,再找其中的第k-p个元素,依次递归。同理,如果第一个数组第p个元素大于第二个数组第q个元素,我们则抛弃第二个数组的前q个元素。当递归遇到k=1时,或者第p个元素=第q个元素时,结束递归。

class Solution:
        
    def findMedianSortedArrays(self, nums1, nums2):
        """
        :type nums1: List[int]
        :type nums2: List[int]
        :rtype: float
        """
        m=len(nums1)
        n=len(nums2)
        k=(m+n)//2
        if (m+n)%2==0: #总长度为偶数
            return (self.findk(nums1,nums2,k)+self.findk(nums1,nums2,k-1))/2
        else: #总长度为奇数
            return self.findk(nums1,nums2,k)
        
    def findk(self,n1,n2,k):
        if len(n1)>len(n2): #确保长度最短的数组排在前面
            return self.findk(n2,n1,k)
        if len(n1)==0:
            return n2[k]        
        if k==1:      
            if n1[0]<n2[0]:
                if len(n1)>1:
                    return min(n1[1],n2[0])
                else:
                    return n2[0]
            else:
                if len(n2)>1:
                    return min(n1[0],n2[1])  
                else:
                    return n1[0]
        if k==0: 
            return min(n1[0],n2[0])
        p=min(k//2-1,len(n1)-1)
        q=k-p-1
        if(n1[p]<n2[q]):
            return self.findk(n1[p+1:],n2,k-p-1)
        elif(n1[p]>n2[q]):
            return self.findk(n1,n2[q+1:],k-q-1)
        else:
            return n1[p]
            

结果84ms,击败100%

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值