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

本文介绍了一种求解两个有序数组中位数的方法,利用中位数特性将数组划分成两个长度相等的部分,通过迭代查找实现O(log(m+n))的时间复杂度。

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

这个题目是不会做的,然后看了题解,这里整理一下思路。

假设数组A和B的长度分别为m, n, 我们首先可以得到如下结论:

  • 如果 (m + n) % 2 == 0, 返回的是排序后index1 = (m + n) // 2 和 index2 = (m + n) // 2 - 1 的平均数
  • 如果 (m + n) % 2 == 1, 返回的是排序后index = (m + n) // 2 的数

解题思路主要利用了中位数的特性:

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

假设数组 A 和 B,分别被分解成了两部分,

  • A[0], A[1], … , A[i-1] | A[i], … , A[m-1]

  • B[0], B[1], …, B[j-1] | B[j], … , B[n-1]

i = 0, 1, 2, … , m; i = 0表示A的左半部分为空, i = m表示 A的右半部分为空; 同理 j = 0, 1, 2, …, n, j = 0表示B的左半部分为空, j = n表示 B的右半部分为空.

如果使其成为中位数,则需满足:

  • i+j==m−i+n−j+δi + j == m - i + n - j + \deltai+j==mi+nj+δm+nm+nm+n为偶数时, δ=0\delta = 0δ=0m+nm+nm+n为奇数时, δ=1\delta = 1δ=1

    i=(m+n+δ)/2−j=(m+n+1)//2−ji = (m + n + \delta) / 2 - j = (m + n + 1) // 2 - ji=(m+n+δ)/2j=(m+n+1)//2j

    这里需要注意的是,假设A、B的长度满足m > n + 1,且当i=m时, j必须取负值以均衡左右两个部分的尺度相同。所以在以下部分,不妨假设A的长度m <= B的长度n.

  • 如果A[i-1]存在的话, A[i-1] <= B[j]

  • 如果B[j-1]存在的话, B[j-1] <= A[i]

class Solution:
    def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:

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

        imin, imax, half = 0, m, (m + n + 1) // 2
        while imin <= imax:
            i = (imin + imax) // 2
            j = half - i
            #print(i, j, nums1, nums2)
            if i > 0 and j < n and nums1[i-1] > nums2[j]:
                imax = i - 1
            elif j > 0 and i < m and nums2[j-1] > nums1[i]:
                imin = i + 1
            else:
                if (m + n) % 2 == 1:
                    if i == 0:
                        return nums2[(m + n) // 2]
                    if j == 0:
                        return nums1[(m + n) // 2]
                    return max(nums1[i-1], nums2[j-1])
 
                if m == 0:
                    return (nums2[(m + n) // 2] + nums2[(m + n) // 2 - 1]) / 2
                
                if i == m:
                    right = nums2[j]
                    if j == 0:
                        left = nums1[i-1]
                    else:
                        left = max(nums1[i-1], nums2[j-1])
                elif i == 0:
                    left = nums2[j-1]
                    if j == n:
                        right = nums1[i]
                    else:
                        right = min(nums1[i], nums2[j])
                else:
                    left = max(nums1[i-1], nums2[j-1])
                    right = min(nums1[i], nums2[j])
                return (left + right) / 2

调了好久的代码终于通过了,但是现在觉得写的还是比较啰嗦,很多逻辑不清楚。需要加强数组方面的逻辑了。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值