leetcode 4 寻找两个有序数组的中位数

给定两个大小为 m 和 n 的有序数组 nums1 和 nums2。

请你找出这两个有序数组的中位数,并且要求算法的时间复杂度为 O(log(m + n))。

你可以假设 nums1 和 nums2 不会同时为空。

示例 1:

nums1 = [1, 3]
nums2 = [2]

则中位数是 2.0
示例 2:

nums1 = [1, 2]
nums2 = [3, 4]

则中位数是 (2 + 3)/2 = 2.5

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/median-of-two-sorted-arrays
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

我的思路非常直接。答案的内存和时间使用情况也都很好,所以就先说自己的想法:(但是这个解法似乎并不能满足时间复杂度的要求)

考虑总共有三种情况:

1.nums1为空。分奇偶直接取数组nums2中位数。

2.nums2为空。分奇偶直接取数组nums1中位数。

3.nums1和nums2均非空。

和取数组中位数一样的思路,把这两个数组按序放进一个新的数组中,直接分奇偶按坐标取新数组的中位数。

遍历一遍自然是O(n+m),由于O(log(n+m))的要求计数统计到一半的时候能取得结果就停下来。

class Solution {
public:
    double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
        int len1=nums1.size();
        int len2=nums2.size();
        if(len1==0)//数组1为空
        {
            if(len2%2==0)//分奇偶取中位数
                return (nums2[len2/2-1]+nums2[len2/2])/2.0;
            else
                return nums2[len2/2];
        }
        if(len2==0)//数组2为空
        {
            if(len1%2==0)
                return (nums1[len1/2-1]+nums1[len1/2])/2.0;
            else
                return nums1[len1/2];
        }
        //均非空
        int len=len1+len2;
        int a[10000];//存归并的数组
        int count=0;
        int p=0;
        int q=0;
        while(count<=len/2)//对每个测试用例只执行到中位数为止(一半)
        {
            if(p>=len1) a[count++]=nums2[q++];//数组1已经没有元素了
            else if(q>=len2) a[count++]=nums1[p++];//数组2已经没有元素了
            //不可能同时没有元素
            else
            {
                if(nums1[p]<nums2[q]) a[count++]=nums1[p++];
                else a[count++]=nums2[q++];
            }
        }
        if(len%2==0) return (a[count-1]+a[count-2])/2.0;
        else return a[count-1];
        return 0;
    }
};

  其实这个思路第三种情况也可以处理前两种,所以前两种代码可省去更美观。但是我写代码一直有贪心的习惯……而且20ms和32ms我觉得是值得写的。

二分思路:(推荐直接看上面链接的标解)

  “中位数”在统计中:将一个集合划分为两个长度相等的子集,其中一个子集中的元素总是大于另一个子集中的元素。

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]

  如果在这两个数组中分别插一根线,就可以将两个数组各分为两部分,这根线的插法要满足:

  1.两个数组的左侧部分长度之和始终等于右侧部分长度之和,因此每个i唯一确定一个j。  (i+j)×2=m+n+1

  2.我们要做的就是不断移动这根线(i的取值)使得左侧部分的所有值小于右侧部分的所有值。由于数组有序,这样的线是必定存在的。

  这两个条件就给出了全部的思路。i的取值为[0,m-1],根据i确定j,然后考虑线左边和右边共四个元素的大小。但是这样时间复杂度为O(min(m,n)),为了达到log级,我们加上第三条处理:

  3.由于数组是顺序的,所以采用二分来选取i的值。

  *最后记得奇偶的处理。

猜你喜欢

转载自www.cnblogs.com/xiying159/p/11699517.html