[Leetcode] Median of Two Sorted Arrays

Median of Two Sorted Arrays 题解

题目来源:https://leetcode.com/problems/median-of-two-sorted-arrays/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

Solution


class Solution {
public:
    double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
        int size1 = nums1.size();
        int size2 = nums2.size();
        if (size1 == 0 && size2 == 0)
            return 0;
        int stopIdx;
        bool oddCountFlag = (size1 + size2) % 2 == 1;
        if (oddCountFlag) {
            stopIdx = (size1 + size2) / 2;
        } else {
            stopIdx = (size1 + size2) / 2 - 1;
        }
        vector<int> tempArr(stopIdx + 2);
        int i = 0, j = 0, k = 0;
        while (i + j <= stopIdx + 1 && i < size1 && j < size2) {
            if (nums1[i] < nums2[j]) {
                tempArr[k++] = nums1[i++];
            } else {
                tempArr[k++] = nums2[j++];
            }
        }
        while (i < size1 && i + j <= stopIdx + 1) {
            tempArr[k++] = nums1[i++];
        }
        while (j < size2 && i + j <= stopIdx + 1) {
            tempArr[k++] = nums2[j++];
        }
        if (oddCountFlag)
            return static_cast<double>(tempArr[stopIdx]);
        else
            return static_cast<double>(tempArr[stopIdx] + tempArr[stopIdx + 1]) / 2.0;
    }
};



解题描述

这道题目大意是,给出两个已经排好序的数组,求这两个数组所有数据的中位数。上面我用到的解法是一个类似与归并排序的方法,对两个数组进行合并,合并到中间的时候停止下来,即可求出中位数。但是时间复杂度是O(m + n)。

虽然交上去是AC了,但是题目要求时间复杂度要O(log (m+n))。确实一时间没想出来怎么达到这个时间复杂度,于是还是翻看了讨论区的解法。讨论区中能达到这个时间复杂度要求的解法使用的是类似二分查找的方法。主要的思想是,对两个数组中较短的一个进行二分查找,找到一个位置作为短数组的分割点cut1,设短数组长为size1,长数组长为size2,则设cut2 = size1 + size2 - cut1,cut2作为长数组的分割点,两个数组分割点的左边数字数目就是所有数据的低半区。只需要满足,cut1左邻居元素小于cut2右邻居元素,cut1右邻居元素大于cut2左邻居元素,我们就找到了所有数据的中间分割位置,就可以求出中位数。所以关键就在于使用二分查找找到这个cut1。

而对于切割的描述,在本文最后给出的参考博客中有更形象的说明:在每个可以切割的位置加上模拟的元素"#",切割只能是在其上进行:


[1 2 3] => [# 1 # 2 # 3 #]

计算出切割的位置之后,需要进行一次位置的映射来找到切割点两边的元素。

具体实现如下:


class Solution {
public:
    double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
        int size1 = nums1.size();
        int size2 = nums2.size();

        // 每次都是对nums1进行二分查找操作,保证nums1长度较短可以减少查找时间
        if (size1 > size2)
            return findMedianSortedArrays(nums2, nums1);

        int low = 0, high = size1 * 2;  // 数组中加上了虚拟的元素"#"作为切割的位置,所以上界是原来的两倍
        int left1, left2, right1, right2, cut1, cut2;
        while (low <= high) {
            cut1 = (low + high) / 2;
            cut2 = size1 + size2 - cut1;

            // 根据切割的位置映射找到切割点两边的元素
            left1 = (cut1 == 0) ? INT_MIN : nums1[(cut1 - 1) / 2];
            left2 = (cut2 == 0) ? INT_MIN : nums2[(cut2 - 1) / 2];
            right1 = (cut1 == 2 * size1) ? INT_MAX : nums1[cut1 / 2];
            right2 = (cut2 == 2 * size2) ? INT_MAX : nums2[cut2 / 2];
            if (left1 > right2)
                high = cut1 - 1;
            else if (left2 > right1)
                low = cut1 + 1;
            else
                break;
        }
        return static_cast<double>(max(left1, left2) + min(right1, right2)) / 2.0;
    }
};

不过这道题Leetcode的测例可能数据量不够,前一种解法跑出来的时间比后一种解法还要长。

参考博客:http://blog.csdn.net/hk2291976/article/details/51107778

posted @ 2018-01-21 20:17  言何午  阅读(95)  评论(0编辑  收藏  举报