第九周作业2(LeetCode4)

1. 题目描述

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

2. 解决思路

这道题的难点主要在于要在题目要求的时间复杂度内考虑不同情况下(也可以说是十分复杂的细节),如何高效地利用二分法来解决这个问题(这里之所以用二分法,是因为要找到nums1[]和nums2[]的各自中位数比大小,nums1Unums2的中位数肯定在这两个数之间,这样就砍掉了一半,进而实现二分)。

而在算法实现过程中,主要要考虑两个关键点:

一、假设nums1比nums2短,那么nums1在1,2对应nums2奇数,偶数,甚至2个,都是不同的情况,要各自单独小心处理,把每一个情况都弄清楚,毕竟奇数个和偶数个的中位数计算方法是不一样的,并且数组太短的话一般方法可能会越界。

二、不是每一次都各砍掉一半的!因为这可能改变nums1Unums2的奇偶性,从而导致中位数计算方法改变。安全同时比较有效的做法是,nums1与nums2每次都砍掉相同的长度,也就是nums1的一半。

其他难点可以看代码中的注释说明
3. 完整代码

package findMedianSortedArrays;

import java.util.Arrays;
import java.lang.Math;  

class Solution {  

    public static void main(String[] args){
        Solution slu = new Solution();
        int nums1[] = {1,3};
        int nums2[] = {2,4};

        double result = slu.findMedianSortedArrays(nums1 , nums2);
        System.out.println("两个排序数组的中位数是:"+result);
    }


    public double findMedianSortedArrays(int[] A, int[] B) {  
        int m = A.length;  
        int n = B.length;  
        if (m <= n)     
            //保证长度短的数组排在前面,方便理解比较
            return findMedianAB(A, m, B, n);  
        return findMedianAB(B, n, A, m);  
    }  

    private double findMedianAB(int[] A, int m, int[] B, int n) {  
        assert(m <= n);  //assertion用于保证程序最基本、关键的正确性,对该boolean表达式进行检查
        if (m == 0) {  
            return median(B, n);  
        }  

        if (m == 1) {  
            if (n == 1)  
                return MO2(A[0], B[0]);  

            if (n % 2 == 1) {  
                return (MO3(B[n/2 - 1], B[n/2 +1], A[0]) + B[n/2]) / 2.0;  
            }  

            return MO3(B[n/2 - 1], B[n/2], A[0]);  //B数组个数为偶数个的情况
        }  

        if (m == 2) {           //之所以要单独分析元素个数为1、2的情况,
                                //是因为使用二分最终减半之后会最终剩下元素个数为1或者2的情况
            if (n == 2) {  
                return MO4(A[0], A[1], B[0], B[1]);  
            }  

            if (n % 2 == 1) {  
                return MO3( B[n/2],  
                        Math.max(A[0], B[n/2 - 1]),  //难点
                        Math.min(A[1], B[n/2 + 1]) );  
            }  

            return MO4( B[n/2], B[n/2 - 1],  
                    Math.max( A[0], B[n/2 - 2] ),  
                    Math.min( A[1], B[n/2 + 1] ) );  
        }  

        int midA = (m - 1) / 2;  //上取整
        int midB = (n - 1) / 2;  
        if (A[midA] <= B[midB]) { 
            return findMedianAB( Arrays.copyOfRange(A, midA, m), m - midA,  
            //可以证明整体的下中位数一定不会被删除
            //偶数的情况,整体上下中位数也都不会被删除;
            //奇数的情况,上下中位数是相等(因为就1个)的)
        }  

        return findMedianAB( Arrays.copyOfRange(A, 0, m - midA), m - midA,  
                Arrays.copyOfRange(B, midA, n), n - midA );  

    }  

    private double MO2(int a, int b) {  //考虑两个数组均只有一个元素的情况
        return (a + b) / 2.0;  
    }  

    private double MO3(int a, int b, int c) {  
    //考虑A数组只有一个元素而B数组元素为除1以外的奇数个的情况下

        return a + b + c - Math.max(a, Math.max(b, c)) - Math.min(a, Math.min(b, c));  
    }  //找到与B数组的中位数求均值(A、B数组和就为偶数个)的第二大的数

    private double MO4(int a, int b, int c, int d) {  
    //依次找到第二大、第三大的数,再求和除以2得到中位数
        int max = Math.max( a, Math.max( b, Math.max( c, d ) ) );  
        int min = Math.min( a, Math.min( b, Math.min( c, d ) ) );  
        return (a + b + c + d - max - min) / 2.0;  
    }  

    private double median(int[] arr, int n) {  
        if (n == 0)  
            return Double.NaN; // error  

        if (n % 2 == 0)  
            return (arr[n / 2] + arr[n / 2 - 1]) / 2.0;  
        return arr[n/2];  
    }  

}  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值