Median of Two Sorted Arrays

本文介绍了一种高效算法,用于求解两个已排序数组合并后的中位数问题,复杂度为O(log(m+n))。通过理解中位数概念及巧妙运用二分查找技巧,实现快速准确地找到中位数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

现给两个已排序的数组nums1和nums2,长度分别为m和n

求两个数组合并后的中位数,要求复杂度为O( log( m+n ) )


  • 例1:
nums1 = [1, 3] 
nums2 = [2]

The median is 2.0
  • 例2:
 nums1 = [1, 2]
 nums2 = [3, 4]

 The median is (2 + 3)/2 = 2.5

虽然二分的复杂度是O( log(n) ),但合并的复杂度是O( n ),只能找trick咯…


题解

原文链接

为了解决这个问题,首先要理解中位数有什么用
在统计学中,中位数用于:“把一个集合分成两个长度相等的子集,其中一个子集的任何一个元素总是大于另一个子集的任何元素(即一个子集中最小的元素大于另一个子集中最大的元素)”
理解了这个,我们就非常接近问题的答案了。


设集合A、B长度分别为m、n
取随机数i满足0<=i<=m , j满足0<=j<=n

首先我们在i位置把A分成左右两部分:

      left_A             |        right_A
A[0], A[1], ..., A[i-1]  |  A[i], A[i+1], ..., A[m-1]

因为A有m个元素,所以有m+1种分法 (i = 0 ~ m)
同时我们知道:len(left_A) = i, len(right_A) = m - i

同样,我们在j位置把B分成左右两部分:

      left_B             |        right_B
B[0], B[1], ..., B[j-1]  |  B[j], B[j+1], ..., B[n-1]

我们把left_A和left_B放在一起称为left_part,同样把right_A和right_B放在一起称为right_part:

      left_part          |        right_part
A[0], A[1], ..., A[i-1]  |  A[i], A[i+1], ..., A[m-1]
B[0], B[1], ..., B[j-1]  |  B[j], B[j+1], ..., B[n-1]

只要我们保证下面两个条件,集合A、B合并之后得到的集合{A, B}就被分成了两个子集left_part和right_part
中位数为 ( max(left_part) + min(right_part) )/2

1) len(left_part) == len(right_part)//长度相等
2) max(left_part) <= min(right_part)//大小关系

1)
len( left_part ) == i + j
len( right_part) == m - i + n - j(或 m-i+n-j+1)
2)
A[i-1] <= A[i] 、B[j-1] <= B[j]
B[j-1] <= A[i] 、A[i-1] <= B[j]

为了满足这两个条件,只需要保证:

(1) i + j == m - i + n - j //m+n为偶数
    i + j == m - i + n - j + 1//m+n为奇数,右边+1就把中位数放在了left_part

(2) B[j-1] <= A[i] and A[i-1] <= B[j]
//因为序列已排序,A[i-1] <= A[i] and B[j-1] <= B[j]已成立

注解:
1、暂时只考虑通常情况,边界情况我们之后再讨论
2、为了方便起见,我们保证n >= m,这样就有:i = 0~m ,j = (m + n + 1)/2 - i //否则j可能为负

所以:
在保证n >= m的情况下,我们使i = 0~m , 则j = (m + n + 1)/2 - i ,此时i、j满足条件(1)。
在此前提下我们只需要找到合适的i,使得B[j-1] <= A[i] 、 A[i-1] <= B[j]即可。

下面给出使用二分法搜索i的伪代码:

<1> imin = 0, imax = m 我们在[imin , imax]区间进行搜索
<2> i = (imin + imax)/2, j = (m + n + 1)/2 - i
<3> 此时i、j满足条件(1),而且我们只会遇到以下三种情况:

  • a) B[j-1] <= A[i] and A[i-1] <= B[j]
    • 条件(2)满足,我们找到了合适的i
  • b) B[j-1] > A[i]
    • 此时A[i]较小,需要增大A[i]
    • 由于序列已排序,A[i]与i正相关,所以我们调整搜索区间为[i+1, imax]
    • goto<2>
  • c) A[i-1] > B[j]
    • 同理,我们调整搜索区间为[imin, i-1]
    • goto<2>

注解:
B[j-1] > A[i]和A[i-1] > B[j]不会同时满足,因为A[i] > A[i-1]、B[j] > B[j-1]

此时我们已经找到了合适的i,所以中位数为:
max(A[i-1], B[j-1])//m+n为奇数,设置j的值时我们把它放在了left_part
(max(A[i-1], B[j-1]) + min(A[i], B[j]))/2 //m+n为偶数由于(m + n + 1)/2 == (m+n)/2


好了,是时候讨论边界情况了:
当取 i=0,i=m,j=0,j=n 时 A[i-1],B[j-1],A[i],B[j]可能不存在

事实上边界情况比想象中的容易处理:

当i、j的取值满足条件(1)时,我们还要做的是保证max(left_part) <= min(right_part)
所以:当i、j不是边界值的时候我们需要保证B[j-1] <= A[i] 和A[i-1] <= B[j];而当A[i-1],B[j-1],A[i],B[j]中的某个不存在时,我们只要不考虑它就可以了。例如i=0时A[i-1]不存在,我们不考虑A[i-1] <= B[j],只要B[j-1] <= A[i]就保证了max(left_part) <= min(right_part)

由此,我们将合适的i的条件修改为:
(j == 0 or i == m or B[j-1] <= A[i]) and (i == 0 or j == n or A[i-1] <= B[j])


最后,给出代码:

 def median(A, B):
    m, n = len(A), len(B)
    if m > n:
        A, B, m, n = B, A, 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 B[j-1] > A[i]:
            # i is too small, must increase it
            imin = i + 1
        elif i > 0 and A[i-1] > B[j]:
            # i is too big, must decrease it
            imax = i - 1
        else:
            # i is perfect

            if i == 0: max_of_left = B[j-1]
            elif j == 0: max_of_left = A[i-1]
            else: max_of_left = max(A[i-1], B[j-1])

            if (m + n) % 2 == 1:
                return max_of_left

            if i == m: min_of_right = B[j]
            elif j == n: min_of_right = A[i]
            else: min_of_right = min(A[i], B[j])

            return (max_of_left + min_of_right) / 2.0

完结撒花~

内容概要:本文详细介绍了900W或1Kw,20V-90V 10A双管正激可调电源充电机的研发过程和技术细节。首先阐述了项目背景,强调了充电机在电动汽车和可再生能源领域的重要地位。接着深入探讨了硬件设计方面,包括PCB设计、磁性器件的选择及其对高功率因数的影响。随后介绍了软件实现,特别是程序代码中关键的保护功能如过流保护的具体实现方法。此外,文中还提到了充电机所具备的各种保护机制,如短路保护、欠压保护、电池反接保护、过流保护和过温度保护,确保设备的安全性和可靠性。通讯功能方面,支持RS232隔离通讯,采用自定义协议实现远程监控和控制。最后讨论了散热设计的重要性,以及为满足量产需求所做的准备工作,包括提供详细的PCB图、程序代码、BOM清单、磁性器件和散热片规格书等源文件。 适合人群:从事电力电子产品研发的技术人员,尤其是关注电动汽车充电解决方案的专业人士。 使用场景及目标:适用于需要高效、可靠充电解决方案的企业和个人开发者,旨在帮助他们快速理解和应用双管正激充电机的设计理念和技术要点,从而加速产品开发进程。 其他说明:本文不仅涵盖了理论知识,还包括具体的工程实践案例,对于想要深入了解充电机内部构造和工作原理的人来说是非常有价值的参考资料。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值