4. Median of Two Sorted Arrays

1、Median of Two Sorted Arrays——这是leedcode的第四题:
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)).
题目意思很简单,两个有序序列,找出这两个有序序列合并后的中位数。时间复杂度要求O(log (m+n));
解决思路:
1、习惯性思路(错误的):
利用排序将两个数组合并成一个数组,然后返回中位数;如果使用这种算法, 时间复杂度是O(m+n),并不能满足要求。
2、正确思路:
这个思路不是我自己想出来,是从讨论区里看到的。这里总结如下:
a、这里将两个序列命名为A、B;
b、将两个序列分别分为左右两个部分分别命名left_part 和right_part:

      left_part          |        right_part
A[0], A[1], ..., A[i-1]  |  A[i], A[i+1], ..., A[m-1]
B[0], B[1], ..., B[j-1]  |  B[j], B[j+1], ..., B[n-1]

c、如果我们可以确保以下两个条件,我们就可以将两个序列分成如上两个部分;
1) len(left_part) == len(right_part) 左边的长度等于右边的长度
2) max(left_part) <= min(right_part)左边最大的数,小于等于右边最小的数。
只要
(1) i + j == m - i + n - j (或者: m - i + n - j + 1)
如果n >= m,化简上面式子,可以得到:当 i = 0 ~ m, j = (m + n + 1)/2 - i
(2) B[j-1] <= A[i] and A[i-1] <= B[j]
d、得到上面的公式之后,其实就可以很清晰的找到那个i,从而得到中位数。但是时间复杂度没达到要求。考虑到两个序列分别有序,所以我们可以使用二分查找,这样时间复杂度就可以达到了。

<1> 令 imin = 0, imax = m, 然后在[imin, imax]中查找i

<2> 令i = (imin + imax)/2, j = (m + n + 1)/2 - i

<3> 此时可以满足len(left_part)==len(right_part).在查找的过程中,会出现如下三种情况:
    <a> B[j-1] <= A[i] and A[i-1] <= B[j]
        如果这个情况,意味着我们找到了那个i,停止查找;
    <b> B[j-1] > A[i]
        意味着A[i]太小了,需要调整i,从而得到B[j-1] <= A[i];这里需要增加i,因为ji是反相关,i增加j就减小。所以我们需要调整i的变动范围从[i+1, imax].所以设置imin = i+1,跳转到<2>继续执行.
    <c> A[i-1] > B[j]
        意味着A[i-1]太大了,同理,需要减小i的值,从而使A[i-1]<=B[j]满足,所以调整查找范围为[imin, i-1]。设置imax = i-1, 跳转到<2>继续执行。

e、这时候,我们需要解决的,就是边界条件问题,当i=0/i=m/j=0/j=n时,A[i-1],B[j-1],A[i],B[j]这些值都是边界值。而我们可以很简单的通过判断就知道中位数在哪里。至此,思路已经很清晰了。
这里贴出Accept的代码:
Java版本:

public class Solution {
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
        int size1 = nums1.length, size2 = nums2.length;
        int max, min;
        int i, j;
        int max_of_left, min_of_right;
        int halfLength = (size1 + size2 + 1) / 2;
        // 如果nums长度大于nums2,就交换
        if (size1 > size2) {
            int temp = size1;
            size1 = size2;
            size2 = temp;
            int[] tempArray = nums1;
            nums1 = nums2;
            nums2 = tempArray;
        }
        min = 0;
        max = size1;
        // 以下是二分查找
        while (min <= max) {
            i = (min + max) / 2;
            j = halfLength - i;
            if (i < size1 && j > 0 && nums1[i] < nums2[j - 1]) {// 前两个条件是确保不会走到边界值,当nums1[i]<nums2[j-1]时,增大查找下限
                min = i + 1;
            } else if (j < size2 && i > 0 && nums2[j] < nums1[i - 1]) {// 前两个条件是确保不会走到边界值,当nums2[j]<nums1[i-1]时,减小查找上限
                max = i - 1;
            } else {
                // 找到这个i,满足条件,可以得到中位数
                // *************************//
                // 以下是边界值的判断
                if (i == 0) {
                    max_of_left = nums2[j - 1];
                } else if (j == 0) {
                    max_of_left = nums1[i - 1];
                } else {
                    // 否则,二者最大的数为左边最大的数
                    max_of_left = nums1[i - 1] > nums2[j - 1] ? nums1[i - 1] : nums2[j - 1];
                }
                // 如果两者之和,是奇数,因为要确保两边的长度一样,也就是
                // i + j == m - i + n - j 或i + j == m - i + n - j + 1
                // 这里设置halfLength = (size1 + size2 + 1) 2;
                // 所以如果两者和为奇数,则左边比右边多一个数,中位数在左边,且是最大的。
                if ((size1 + size2) % 2 == 1) {
                    return max_of_left;
                }
                if (i == size1) {
                    min_of_right = nums2[j];
                } else if (j == size2) {
                    min_of_right = nums1[i];
                } else {
                    min_of_right = nums1[i] < nums2[j] ? nums1[i] : nums2[j];
                }
                return ((float) (max_of_left + min_of_right)) / 2;
            }
        }
        return 0;
    }
}

C++版本:

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);
        }
        int min = 0, i;
        int max = m, j;
        int halfLength = (m + n + 1) >> 1;
        while (min <= max) {
            i = (min + max) >> 1;
            j = halfLength - i;
            if (j > 0 && i < m&&nums1[i] < nums2[j - 1]) {
                min = i + 1;
            }
            else if (i > 0 && j < n&&nums2[j] < nums1[i - 1]) 
            {
                max = i - 1;
            }
            else
            {
                int maxOfLeft;
                if (i==0)
                {
                    maxOfLeft = nums2[j - 1];
                }
                else if(j==0)
                {
                    maxOfLeft = nums1[i - 1];
                }
                else
                {
                    maxOfLeft = nums1[i - 1] > nums2[j - 1] ? nums1[i - 1] : nums2[j - 1];
                }
                if ((m+n)%2==1)
                {
                    return maxOfLeft;
                }
                int minOfRight;
                if (i==m)
                {
                    minOfRight = nums2[j];
                }
                else if (j==n)
                {
                    minOfRight = nums1[i];
                }
                else
                {
                    minOfRight = nums1[i] < nums2[j] ? nums1[i] : nums2[j];
                }
                return ((float)minOfRight + maxOfLeft) / 2;
            }
        }
        return 0;
    }

};

你可能感兴趣的:(4. Median of Two Sorted Arrays)