Leetcode 4 Median of Two Sorted Arrays(二分)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/wr339988/article/details/56962618

题目链接:https://leetcode.com/problems/median-of-two-sorted-arrays/?tab=Description

Description

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

解题思路

这道题目我想了很久,看着复杂度都知道只能用二分,但是如何二分是个问题。一开始我想的是找出最中间的4到5个数,最后直接求中位数就行了,然而这种方法要考虑的情况太多了,实现起来很复杂。最后看了一下别人的解题思路,才发现忘记了关键的一个点:两个切分点将两个数组分别分成左右两个部分,左边元素个数之和是等于右边元素个数之和的。

首先,我们来看看中位数是怎么得到的。对于[2 3 5 7],我们可以在3和5之间切一刀,即:

[2 3 / 5 7]

如果数组长度为奇数,可以认为切分点就是在最中间的数上,比如对于[2 3 4 5 7],左半部为(2,3,4),右半部为(4,5,7):

[2 3 (4/4) 5 7]

有了切分点的概念后,我们可以通过“想象”在元素之间添加切分点去除对数组长度奇偶不同时的考虑,以下面的数组为例:

[6 9 13 18] -> [# 6 # 9 # 13 # 18 #] (N = 4)
position index 0 1 2  3 4 5  6 7 8 (N_Position = 9)

[6 9 11 13 18]-> [# 6 # 9 # 11 # 13 # 18 #] (N = 5)
position index   0 1 2  3 4 5  6 7 8  9 10 (N_Position = 11)

中位数左右长度必须相等,故而若数组1切分位置C1为2,则数组2切分位置C2为(4+5-2)=7,即:

[6 9 13 18] -> [# 6 / 9 # 13 # 18 #] (N = 4)
position index 0 1 2  3 4 5  6 7 8 (N_Position = 9)

[6 9 11 13 18]-> [# 6 # 9 # 11 # (13/13) # 18 #] (N = 5)
position index   0 1 2  3 4 5  6  7    8  9 10 (N_Position = 11)

这样,我们只需要关注最靠近两个切分点的四个数的大小即可,即:

L1 = A1[(C1-1)/2]; R1 = A1[C1/2];
L2 = A2[(C2-1)/2]; R2 = A2[C2/2];

在这个例子中,我们有:

L1 = A1[(2-1)/2]=A1[0]=6; R1 = A1[2/2]=A1[1]=9;
L2 = A2[(7-1)/2]=A2[3]=13; R2 = A2[7/2]=A2[3]=13;

那么什么样的切分点是我们要找的切分点呢?我们知道,中位数左边的部分一定要比右边的部分小,即:

max(L1,L2)<=min(R1,R2)

而L1<=R1和L2<=R2是自然成立的,所以只需要比较L1和R2以及L2和R1的大小就可以了。首先保证数组1的长度比数组2的长度要小,这样只需要在数组1查找切分点即可了。然后通过二分来查找最佳切分点,初始化left=0,right=2*N1,每次都在区间[left,right]寻找切分点,设切分点为C1=(left+right)/2。如果L1>R2,说明C1偏右了,要向左移一些,此时令right=C1-1;否则说明C1偏右了,此时令left=C1+1。接着继续二分查找,直到找到满足条件的切分点。这里要注意边界情况,即C1=0或C1=2*N1,对于C2来说也是如此。

AC代码

class Solution {
public:
    double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
        int m=nums1.size(),n=nums2.size();
        if(m>n) return findMedianSortedArrays(nums2,nums1);

        if(m==0)    return (1.0*nums2[n/2]+1.0*nums2[(n-1)/2])/2;

        int left=0,right=2*m;
        int i,j;
        double l1,l2,r1,r2;
        while(left<=right){
            i=(left+right)/2;
            j=m+n-i;

            l1=(i==0)?INT_MIN:nums1[(i-1)/2];
            r1=(i==m*2)?INT_MAX:nums1[i/2];
            l2=(j==0)?INT_MIN:nums2[(j-1)/2];
            r2=(j==n*2)?INT_MAX:nums2[j/2];
            if(l1>r2)   right=i-1;
            else if(l2>r1)  left=i+1;
            else    return (max(l1,l2)+min(r1,r2))/2;
        }
    }
};

猜你喜欢

转载自blog.csdn.net/wr339988/article/details/56962618