LeetCode || Median of Two Sorted Arrays

Median of Two Sorted Arrays

  Total Accepted: 9557  Total Submissions: 57293 My Submissions

There are two sorted arrays A and B of size m and n respectively. Find the median of the two sorted arrays. The overall run time complexity should be O(log (m+n)).

大意是在两个排好序(升序)的数组A, B中找到median值并返回,二者长度分别为m、n,median值的定义是如果一共有奇数个元素,那么返回中间位置的那个数,如果有偶数个元素,返回中间两个位置元素的平均值。时间复杂度要求为 O(log(m+n))。

2、思路一:首先想到的最基本的方法就是:将A, B merge到一个长数组C中,然后对C进行快速排序,最后直接取到中间位置的median值,时间复杂度为:O((M+N)log(m+n)),主要消耗在排序上,显然不符合题目要求。
     思路二:同样对A,B进行merge,但是一边merge,一边记录着索引值,一旦merge到了中间位置的元素,就可以结束了,返回median,这样做虽然没有使用(m+n)时间,但是复杂度应该也算作O(m+n),所以也不行。
      解决方法:最后在一个博客中看到了某大神的代码,只有三十二行,思路是利用分治法寻找第K小元素的策略,如果m+n为奇数,那么最后的median为一个现有的数组元素,也即寻找A,B整体中的第K小元素,K=(m+n)/2+1,例如m+n=5,时就是找第3小的元素;如果m+n为偶数,那么就可以分为两步,先找第K=(m+n)/2小元素,再找到第 K+1 小的元素,最后二者取平均值即为median值。
         具体在两个已排序数组A,B中如何寻找第K小元素呢?根据分治法策略,是进行一次次的迭代(递归),每次迭代都将寻找的范围缩小一部分。做法是比较 x=A[(k/2)-1] 与 y=B[(k/2)-1]:
        (1)如果二者相等,那么返回二者中任何一个都是第K小的,因为 在A中有 k/2-1 个元素比二者小,在B中也有 k/2-1 个元素比二者小,一共 k-2 个,再算上二者正好为 K个元素,因为二者相等,故都可以作为第K小元素;
        (2)如果 x<y ,说明A中所有 x 及之前的元素都一定在最终的第K小元素之前出现,因为 x与y 及其前面的元素一共才 K 个。 接下来就可以不再考虑 x及其之前的元素了,这步就是分治法缩小处理范围的步骤,下面就在 A中x之后的元素和B中继续迭代,找出第 K-K/2 小的元素;可见,每次都能把范围缩小 K/2,而K正好是与 m+n 相关的(K=(m+n)/2或者(m+n)/2+1);
        (3)如果 x>y ,说明B中所有 y 及之前的元素都一定在第K小元素之前出现,接下来继续在 A以及B的 y 之后的元素中寻找第 K-K/2 小的元素。
        
编码实现需要注意的地方:
    (1)首先要判断A,B中是否A更短,否则将A,B交换位置重新调用函数,即给函数传递参数时要把短的放在前面,原因在下面会有解释;
    (2)首先要判断A,B数组是否某个为空,即没有元素,此时只需返回非空的那个数组中第K个元素即可。因为不可能两个数组同时为空,而且在(1)中我们已经把短的数组放在了前面,所以这步只需要判断数组A是否长度为0即可;
    (3)在判断 x与y 的大小关系时,还要注意看 A中的元素个数 m 与 k/2 的大小关系,如果 m<k/2,说明A中元素相对来说很少,此时我们显然不存在 A[k/2-1] 这个元素了,这是我们只能取 A[m-1] 来代替,也即取二者中的较小值,即 min(m,k/2)。
    (4)迭代(递归)结束的条件是:1、A,B中其中一个为空;2、K=1,此时只需返回 A[0]和B[0] 中较小的值。

代码如下:
class Solution {
    double findKth(int A[], int m, int B[], int n, int k){
        if(m>n)
            return findKth(B, n, A, m, k);
        if(m==0)
            return B[k-1];
        if(k==1)
            return min(A[0], B[0]);
        else{
            int sa=min(m, k/2), sb=k-sa;
            if(A[sa-1]==B[sb-1])
                return A[sa-1];
            else if(A[sa-1]<B[sb-1])
                return findKth(A+sa, m-sa, B, n, k-sa);
            else
                return findKth(A, m, B+sb, n-sb, k-sb);
        }
    }
public:
    double findMedianSortedArrays(int A[], int m, int B[], int n) {
        int total=m+n;
        int k=total/2;
        if(total%2)
            return findKth(A, m, B, n, k+1);
        else
            return (findKth(A, m, B, n, k)+findKth(A, m, B, n, k+1))/2;
    }
};

心得体会:
        开始读完题时,没有思路,尤其是对于时间复杂度要求为  O(log (m+n)),根本无从下手,看完大神的代码,才有些感触。
        对于能用遍历(O(N))解决的问题,首先要考虑能否用排序(O(N*logN))解决,如果还不满足要求,那么就考虑能否将问题转化为分治、二分查找这些时间复杂度为 O(logN) 的策略。





评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值