Q4 Median of Two Sorted Arrays 两个有序数组的中位数

题目:

There are two sorted arrays nums1 and nums2 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)).

Example 1:

nums1 = [1, 3]

nums2 = [2]

 

The median is 2.0

Example 2:

nums1 = [1, 2]

nums2 = [3, 4]

 

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

----------------------------------------------------------------------------------

思路:

首先来定义一些符号。我们将输入的两个数组表示为a, b,并假定它们的元素个数分别为m, n . 其中, 表示a数组的第i个元素, 表示b数组的第i个元素。

然后,我们要先做一些假设,做这些假设是为了方便思考。(对于不符合这些假设的情况,我们将在后面进行处理)。

假设1:中位数出自数组a,并假定此中位数为 . (事实上,中位数有可能出自数组a,也有可能出自数组b )。

假设2:m+n为奇数

假设3:在中位数的两端,都既有a数组的元素也有b数组的元素

 

此时情况如下图所示:

其中,

(式 1)

(式2)

 

由于 是中位数,所以 两边的元素个数应该是相等的,即:

化简,得:

(式3)

注意,y与x的大小是反相关的。

至此,问题便转化为:利用数组的有序性,找出满足 式1、式2、式3 的

 

对于某个x,通过式3,y的值可以唯一确定(通过式3确定出来的y的实际意义是:当正好插入到后面时,两边的元素个数正好相等)

1.如果这组x,y也满足式2,则此 便是所求的中位数;

2.如果 ,则说明如果按照大小排序,应当插入到的前方。这意味着,左边的元素个数就会少于右边的元素个数。即当前的 太小了,亦即x太小了,所以需要在 [ x+1, r ] 的范围内继续搜索;

3.如果,则说明如果按照大小排序,应当插入到的后方。这意味着,左边的元素个数就会多于右边的元素个数。即当前的 太大了,亦即x太大了,所以需要在 [ l, x-1 ] 的范围内继续搜索;

 

通过上述描述,写出二分查找就很容易了。

接下来,我们对不满足三个假设的情况进行处理。

 

1.首先看假设1,对于中位数出自b的情况,其实很容易处理:如果在a中没有找到中位数,只需要将两个数组反着传入函数调用一次,在b中再找一遍就好了;

 

2.对于假设2,也比较好处理。我们假设为处于前面的那个中位数。此时 左边的元素比右边少一个,列出等式,化简,易得:。找到符合条件的后, 即为所求;

 

3.对于假设3,处理起来就有些麻烦了。其麻烦之处在于,通过式3求出来的y值可能不在[0,n-1]的值域里。针对落在不同的区域内的y的情况,我们需要分类讨论。

1)当 时,左边b元素的个数为负,无实际意义,说明x太大了,因此需要在[ l, x-1 ] 的范围内继续搜索

2)当 时,左边b元素的个数为0,有实际意义。此时式2弱化为

I)如果 ,则 即为所求;

II)如果 ,则x太大了,应该在[ l, x-1 ]的范围内继续搜索

3)当时,

I)如果这组x,y也满足式2,则此 便是所求的中位数;

II)如果 ,则说明如果按照大小排序,应当插入到的前方。这意味着,左边的元素个数就会少于右边的元素个数。即当前的 太小了,亦即x太小了,所以需要在 [ x+1, r ] 的范围内继续搜索

III)如果,则说明如果按照大小排序,应当插入到的后方。这意味着,左边的元素个数就会多于右边的元素个数。即当前的 太大了,亦即x太大了,所以需要在 [ l, x-1 ] 的范围内继续搜索

4)当时,右边b元素的个数为负,无实际意义。说明x太小了,所以需要在 [ x+1, r ] 的范围内继续搜索

 

我们对上述条件进行合并和化简,得:

If () || ( && )时,在 [ l, x-1 ] 的范围内继续搜索

If ( &&)|| (),在 [ x+1, r ] 的范围内继续搜索

Else,

If为奇数,返回

If为偶数,返回 (这里由于有x+1和y+1这种写法,因此下标有可能越界,在代码中可以看到我对越界的情况进行了处理)

 

-------------------------------------------------------------------------------------------------------------------

代码:

 

class Solution {
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
        Double rst = findMedium(nums1, nums2);
        if(rst != null) return rst;
        return findMedium(nums2, nums1);
    }
    
    private Double findMedium(int[] a, int[] b) {
    	int m = a.length, n = b.length;
    	boolean isOdd = ((m + n) % 2 == 1);
        int l = 0, r = m - 1;
        while( l <= r ) {
            int x = (l+r)/2;
            int y;
            if(isOdd) y = (m + n - 3 - 2*x) / 2;
            else y = (m + n - 4 - 2*x) / 2;
            if((y>=0 && y <= n-1 && a[x] < b[y]) || y > n - 1) {  // right
                l = x + 1;
            }else if((y<=-2) || (y>=-1 && y<n-1 && a[x] > b[y+1])) {  //left
                r = x - 1;
            }else {  //return answer
                if(isOdd) return (double) a[x];
                else {
                    return (double)(a[x] + Math.min(
                            x+1<=m-1?a[x+1]:Integer.MAX_VALUE, 
                            y+1<=n-1?b[y+1]:Integer.MAX_VALUE)) / 2;
                }
            }
        }
    	return null;
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值