4. 寻找两个正序数组的中位数(困难)

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

1. 题目描述

题目中转:4. 寻找两个正序数组的中位数
在这里插入图片描述
在这里插入图片描述

2.详细题解

   两个有序数组,寻找二者的中位数,最直观的方法是先归并这两个数组为一个有序数组,中位数则为中间的数字,算法时间复杂度为 O ( l o g ( m + n ) ) O(log(m+n)) O(log(m+n)),具体代码实现见Python方法一
  要求时间复杂度不大于 O ( l o g ( m + n ) ) O(log (m+n)) O(log(m+n))时间复杂度,首先肯定不能先归并两个数组了,两个数组均有序,应当充分运用这个条件。
  思考什么是中位数?通俗的说,即将数据一分为二,且其中一个集合中数据最大值小于等于另一个集合中数据的最小值。
  中位数性质已经很明晰。因此,对于题目中的两个数组,相当于要在数组 1 1 1(长度为 m m m)和数组 2 2 2(长度为 n n n)中分别寻找一个位置 i i i j j j,将两个数组一分为二,两个数组的左半部分构成一个集合,右半部分构成另一个集合。 i i i j j j的取值范围分别为 [ 0 , m ] [0, m] [0,m] [ 0 , n ] [0,n] [0,n],此时左集合和右集合的元素个数应满足如下关系:
   i + j = m − i + n − j i+j = m -i + n - j i+j=mi+nj 或者 i + j = m − i + n − j + 1 i+j = m -i + n - j + 1 i+j=mi+nj+1
  上述等式分别表示 m + n m+n m+n为偶数和奇数的情况,推导可得:
   i + j = ( m + n ) / 2 i + j= (m+n)/2 i+j=(m+n)/2 i + j = ( m + n + 1 ) / 2 i + j= (m+n+1)/2 i+j=(m+n+1)/2,二者可合并为 i + j = ( m + n + 1 ) / 2 i + j= (m+n+1)/2 i+j=(m+n+1)/2,仅保留整数结果。
  进一步可得 j = ( m + n + 1 ) / 2 − i j = (m+n+1)/2 - i j=(m+n+1)/2i,因为 i i i j j j的取值范围分别为 [ 0 , m ] [0, m] [0,m] [ 0 , n ] [0,n] [0,n],因此 m < = n m<=n m<=n时该等式成立,否则当 i = m i=m i=m时,显然不能均分该两个数组,因此应首先判断两个数组的长度,将长度更小的数组作为第一个数组
  接下来进行二分条件分析,对于第一个数组,取中间值为 i = ( l e f t + r i g h t ) / / 2 i=(left+right)//2 i=(left+right)//2,则左边界值为 n u m s 1 [ i − 1 ] nums1[i-1] nums1[i1],右边界值为 n u m s 1 [ i ] nums1[i] nums1[i];随之确定第二个数组的分割为 j j j,左边界值为 n u m s 2 [ j − 1 ] nums2[j-1] nums2[j1],右边界值为 n u m s 2 [ j ] nums2[j] nums2[j],此时 n u m s 1 [ i − 1 ] < = n u m s 1 [ i ] nums1[i-1]<=nums1[i] nums1[i1]<=nums1[i] n u m s 2 [ j − 1 ] < = n u m s 2 [ j ] nums2[j-1]<=nums2[j] nums2[j1]<=nums2[j]肯定是成立的(因为有序),因此我们需要确定一个 i i i,使如下等式成立:

n u m s 1 [ i − 1 ] ≤ n u m s 2 [ j ] 且 n u m s 2 [ j − 1 ] ≤ n u m s 1 [ i ] nums1[i−1]≤nums2[j] 且 nums2[j−1]≤nums1[i] nums1[i1]nums2[j]nums2[j1]nums1[i]

  但该条件等于仅需等价于寻找最大的 i i i使得如下等式成立,因为随着 i i i递增, j j j是减小的,若 i i i是最大的,说明 i + 1 i+1 i+1不成立,此时有 n u m s [ i ] > n u m s 2 [ j − 1 ] nums[i]>nums2[j−1] nums[i]>nums2[j1].

nums1[i-1]<=nums2[j]$

  因此二分条件判断如下:

n u m s 1 [ i − 1 ] < = n u m s 2 [ j ] nums1[i-1] <= nums2[j] nums1[i1]<=nums2[j]成立,此时说明 i i i可能不是最大值,可进一步探索, l e f t = i + 1 left = i + 1 left=i+1
否则,即 n u m s 1 [ i − 1 ] > n u m s 2 [ j ] nums1[i-1] > nums2[j] nums1[i1]>nums2[j],说明分界点 i i i大了,故 r i g h t = i − 1 right = i - 1 right=i1

具体实现见Python方法二Java实现

3.代码实现

3.1 Python

方法一:

class Solution:
    def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:
        res = []
        left, right = 0, 0
        m, n = len(nums1), len(nums2)
        while left < m and right < n:
            if nums1[left] <= nums2[right]:
                res.append(nums1[left])
                left += 1
            else:
                res.append(nums2[right])
                right += 1
        if left < m:
            res.extend(nums1[left:])
        if right < n:
            res.extend(nums2[right:])

        mid = (m + n ) // 2
        if (m+n) % 2 == 0:
            return (res[mid] + res[mid-1]) / 2
        else:
            return res[mid]

在这里插入图片描述
方法二:

class Solution:
    def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:
        m, n = len(nums1), len(nums2)
        if m > n:
            return self.findMedianSortedArrays(nums2, nums1)

        infinty = pow(10, 7)
        med1, med2 = 0, 0
        left, right = 0, m
        while left <= right:
            i = (left +right) // 2
            j = (m + n + 1) // 2 - i

            nums1_left = -infinty if i == 0 else nums1[i-1]
            nums1_right = infinty if i == m else nums1[i]
            nums2_left = -infinty if j == 0 else nums2[j-1]
            nums2_right = infinty if j == n else nums2[j]

            if nums1_left <= nums2_right:
                med1, med2 = max(nums1_left, nums2_left), min(nums1_right, nums2_right)
                left = i + 1
            else:
                right = i - 1
        return (med1 + med2) / 2 if (m + n) % 2 == 0 else med1
        

在这里插入图片描述

3.2 Java

class Solution {
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
        int m = nums1.length;
        int n = nums2.length;
        if (m > n){
            return findMedianSortedArrays(nums2, nums1);
        }
        int left = 0, right = m;
        int med1 = 0, med2 = 0;
        while (left <= right){
            int i = (left + right) / 2;
            int j = (m + n + 1) / 2 - i;
            int nums1_left = i == 0 ? Integer.MIN_VALUE : nums1[i-1];
            int nums1_right = i == m ? Integer.MAX_VALUE : nums1[i];
            int nums2_left = j == 0 ? Integer.MIN_VALUE : nums2[j-1];
            int nums2_right = j == n ? Integer.MAX_VALUE : nums2[j];
            if (nums1_left <= nums2_right){
                med1 = Math.max(nums1_left, nums2_left);
                med2 = Math.min(nums1_right, nums2_right);
                left = i + 1;
            }else{
                right = i - 1;
            }
        }
        return (m + n) % 2 == 0 ? (med1 + med2) / 2.0 : med1;
    }
}

在这里插入图片描述

  执行用时不必过于纠结,对比可以发现,对于python和java完全相同的编写,java的时间一般是优于python的;至于编写的代码的执行用时击败多少对手,执行用时和网络环境、当前提交代码人数等均有关系,可以尝试完全相同的代码多次执行用时也不是完全相同,只要确保自己代码的算法时间复杂度满足相应要求即可,也可以通过点击分布图查看其它coder的code。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

raykingl

你的鼓励将是我创作的最大动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值