Leetcode学习(python语言)

4.寻找两个正序数组的中位数

4.1题目

1.2解决方法

方法一

直接将两个数组合并,但不符合时间复杂度=O(log (m+n)) ,速度:17ms

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

方法二

二分法,符合时间复杂度=O(log (m+n)),速度:21ms

class Solution(object):
    def findMedianSortedArrays(self, nums1, nums2):
        """
        :type nums1: List[int]
        :type nums2: List[int]
        :rtype: float
        """
        if len(nums1)>len(nums2):
            nums1, nums2 = nums2, nums1
        m, n = len(nums1), len(nums2)
        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 nums1[i] < nums2[j-1]:
                imin = i + 1
            elif i > 0 and nums1[i-1] > nums2[j]:
                imax = i - 1
            else:
                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.0

       

1.3方法二(二分法)解释

当我们需要在两个已排序数组 nums1nums2 中找到它们的中位数时,可以使用二分查找的方法来解决。这里给出的代码使用了这种方法来有效地找到中位数。

1.3.1代码解释及原理

1)算法原理
  • 给定两个已排序的数组 nums1nums2,长度分别为 mn
  • 中位数定义:如果数组长度之和 (m + n) 是奇数,则中位数是第 (m + n) // 2 + 1 个元素;如果是偶数,则中位数是第 (m + n) // 2 和第 (m + n) // 2 + 1 个元素的平均值。
2) 二分查找策略
  • 为了优化查找速度,选择在长度较短的数组 nums1 上进行二分查找。
  • 设定 iminimax 分别为 nums1 中元素的范围,初始时 imin = 0imax = m,其中 m = len(nums1)
3) 二分查找过程
  • 计算 i 作为 nums1 的分割点:i = (imin + imax) // 2
  • 计算 j 作为 nums2 的分割点:j = half_len - i,其中 half_len = (m + n + 1) // 2
    • half_len = (m + n + 1) // 2的原因:(m + n + 1) // 2 的计算方法确保了在奇数和偶数情况下都能正确地找到中位数的位置,是处理这类问题的常见做法。
  • inums1 中的分割点索引,它将 nums1 分成左右两部分:nums1[0:i-1]nums1[i:m-1]
  • jnums2 中的分割点索引,它将 nums2 分成左右两部分:nums2[0:j-1]nums2[j:n-1]。
    • 根据二分查找的思路,我们要确保左侧部分的元素个数等于右侧部分的元素个数,即 len(nums1[0:i-1]) + len(nums2[0:j-1]) = len(nums1[i:m-1]) + len(nums2[j:n-1])。为了保证这个条件,我们需要调整 ij 的值,直到找到满足条件的分割点。
4) 满足条件的分割点
  • 如果 i < mnums1[i] < nums2[j-1],说明 i 太小,需要增加 i 以增大 nums1[i],使得左侧部分的元素全部小于右侧部分的元素。
  • 如果 i > 0nums1[i-1] > nums2[j],说明 i 太大,需要减小 i 以减小 nums1[i-1],同样保证左侧部分的元素全部小于右侧部分的元素。
5) 边界情况处理
  • 对于 i == 0 的情况,意味着 nums1 中的所有元素都在右侧,因此左侧部分没有任何元素。这时,我们需要考虑左侧最大值。由于 nums2 在右侧的所有元素是 nums2[j:n-1],那么左侧的最大值应该是 nums2[j-1],而不是 nums2[j]。这是因为 j 是分割点,nums2[j-1] 是在 nums2[0:j-1] 中的最后一个元素。
  • 因此,在这种情况下,我们取 nums2[j-1] 作为左侧的最大值,因为它是 nums2 中左侧部分的最后一个元素。
  • 这种设计确保了在每一步迭代中,根据当前的分割点 ij,能够正确地确定左侧和右侧的边界值,从而实现有效的二分查找和中位数计算。 
  • 确定左侧最大值 (max_of_left)

    • 如果 i 等于 0,说明 nums1 中的所有元素都在右侧,因此左侧最大值取 nums2[j - 1]
    • 如果 j 等于 0,说明 nums2 中的所有元素都在右侧,因此左侧最大值取 nums1[i - 1]
    • 否则,取 nums1[i - 1]nums2[j - 1] 中较大的值作为左侧最大值。
  • 判断数组长度之和的奇偶性

    • 如果 (m + n) % 2 == 1,即总元素个数为奇数,则直接返回 max_of_left 作为中位数。
  • 确定右侧最小值 (min_of_right)

    • 如果 i 等于 m,说明 nums1 中的所有元素都在左侧,右侧最小值取 nums2[j]
    • 如果 j 等于 n,说明 nums2 中的所有元素都在左侧,右侧最小值取 nums1[i]
    • 否则,取 nums1[i]nums2[j] 中较小的值作为右侧最小值。
  • 计算中位数

    • 如果 (m + n) % 2 == 1,直接返回 max_of_left
    • 否则,返回 (max_of_left + min_of_right) / 2.0,即左侧最大值和右侧最小值的平均值作为中位数。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值