LeetCode算法笔记4

题目描述:

给定两个大小分别为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的 中位数 。

算法的时间复杂度应该为 O(log (m+n)) 。

示例 1:

输入:nums1 = [1,3], nums2 = [2]
输出:2.00000
解释:合并数组 = [1,2,3] ,中位数 2

示例 2:

输入:nums1 = [1,2], nums2 = [3,4]
输出:2.50000
解释:合并数组 = [1,2,3,4] ,中位数 (2 + 3) / 2 = 2.5

解法:

class Solution:
    def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:
        # Ensure nums1 is the smaller array
        if len(nums1) > len(nums2):
            nums1, nums2 = nums2, nums1
        
        m, n = len(nums1), len(nums2)
        left, right = 0, m
        half_len = (m + n + 1) // 2
        
        while left <= right:
            i = (left + right) // 2
            j = half_len - i
            
            if i < m and nums2[j - 1] > nums1[i]:
                left = i + 1
            elif i > 0 and nums1[i - 1] > nums2[j]:
                right = 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. 确保 nums1 是较短的数组

if len(nums1) > len(nums2): nums1, nums2 = nums2, nums1

这一部分代码首先比较 nums1nums2 的长度,如果 nums1 较长,通过交换使得 nums1 成为较短的数组。这样做是为了简化后续的二分查找过程,因为在二分查找中,我们希望在较短的数组上进行操作,以确保效率和简洁性。

2. 初始化变量和二分查找准备

m, n = len(nums1), len(nums2)
left, right = 0, m
half_len = (m + n + 1) // 2
  • m 和 n 分别是 nums1 和 nums2 的长度。
  • left 和 right 是用于二分查找的指针,初始化为 0 和 m
  • half_len 是两个数组合并后的中间位置。如果总长度为奇数,half_len 是左边部分的长度,如果是偶数,half_len 是左边部分加一的长度。

3. 开始二分查找

while left <= right:
    i = (left + right) // 2
    j = half_len - i

这里开始了二分查找的循环。inums1 中的分割点,jnums2 中的分割点。每次迭代,我们计算 ij 的值,并根据它们来调整 leftright 的位置,以缩小搜索范围。

4. 分割点位置的判断和调整

if i < m and nums2[j - 1] > nums1[i]:
    left = i + 1
elif i > 0 and nums1[i - 1] > nums2[j]:
    right = i - 1
else:
    # Found the correct partition
    ...
  • 如果 i 太小,意味着 nums1[i] 太小,需要增加 i,即将 left 向右移动。
  • 如果 i 太大,意味着 nums1[i] 太大,需要减小 i,即将 right 向左移动。
  • 当找到合适的 i 时,即 i 满足分割条件时,执行下一步操作。

5. 计算中位数

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
  • 计算左半部分的最大值 max_of_left

    • 如果 i 为 0,则 nums1 的左半部分为空,最大值为 nums2[j - 1]
    • 如果 j 为 0,则 nums2 的左半部分为空,最大值为 nums1[i - 1]
    • 否则,取 nums1[i - 1] 和 nums2[j - 1] 的较大值。
  • 如果总长度是奇数,直接返回 max_of_left

  • 计算右半部分的最小值 min_of_right

    • 如果 i 等于 m,则 nums1 的右半部分为空,最小值为 nums2[j]
    • 如果 j 等于 n,则 nums2 的右半部分为空,最小值为 nums1[i]
    • 否则,取 nums1[i] 和 nums2[j] 的较小值。
  • 最后,如果总长度是偶数,返回左半部分的最大值 max_of_left 和右半部分的最小值 min_of_right 的平均值作为中位数。

这样,整个算法通过二分查找的方式,有效地找到了两个已排序数组的中位数,同时保证了时间复杂度在 O(log (m+n)) 的范围内。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值