leecode4:寻找两个正序数组的中位数

1.题目描述

给定两个大小分别为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的 中位数 。

2.示例

示例 1:

输入:nums1 = [1,3], nums2 = [2]
输出:2.00000
解释:合并数组 = [1,2,3] ,中位数 2

示例 2:

输入:nums1 = [0,0], nums2 = [0,0]
输出:0.00000

示例 3:

 输入:nums1 = [1,2], nums2 = [3,4]
 输出:2.50000
 解释:合并数组 = [1,2,3,4] ,中位数 (2 + 3) / 2 = 2.5

3.分析

此题难度不大,有如下思路

(1)最简单的想法是,将一个数组的每一个元素,按照升序通过插入法等方法将两个数组合并。然后根据奇偶性质找出中位数的位置并计算。

但是这种方法不是高效的,空间上它需要重新申请一个m+n长度的新数组。至少也需要将较短的那个数组重新申请空间到较长的那个数组上。

时间上,由于每次需要将一个元素有序插入到另一个数组中,时间也会有较大的浪费。

(2)根据上面的方法,时间浪费的原因在于没有利用好两个数组已经有序的条件。改进的方法,不再将两个数组和并,也不关心中位数之后的元素

的排序。通过两个数组的元素和计算出中位数的位置,设置指向两个数组的两个游标进行移动。在两个数组的元素都没被遍历完时,比较当前两个游标对应的元素大小,使较小元素的游标后移。

在某一个数组已经被比较完时,则将另一个数组的元素顺序不动遍历即可,直到整体的游标数到达中位数的位置。

这样就提高了时间和空间的效率,类似流的不保存元素的值,只关心中位数的位置。达到了空间复杂度为O(m+n)

4.代码

class Solution {
public:
    double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
        int total = nums1.size() + nums2.size();//总元素数
        int numPos1 = 0;//数组1的游标
        int numPos2 = 0;//数组2的游标
        int counter = 0;//计数器
        float result =0;//结果值

        if(total%2!=0){//奇数
            while(counter<total/2){
                if(numPos1<nums1.size()&&numPos2<nums2.size()){
                    if(nums1.at(numPos1)<nums2.at(numPos2))   numPos1++;
                    else    numPos2++;
                }
                else if(numPos1<nums1.size())  numPos1++;
                else    numPos2++;
                counter++;
            }
            if(numPos1<nums1.size()&&numPos2<nums2.size()){
                    if(nums1.at(numPos1)<nums2.at(numPos2))   result+=nums1.at(numPos1);
                    else    result+=nums2.at(numPos2);
                }
                else if(numPos1<nums1.size())  result+=nums1.at(numPos1);
                else    result+=nums2.at(numPos2);

        }else{//偶数
            while(counter<total/2-1){
                if(numPos1<nums1.size()&&numPos2<nums2.size()){
                    if(nums1.at(numPos1)<nums2.at(numPos2))   numPos1++;
                    else    numPos2++;
                }
                else if(numPos1<nums1.size())  numPos1++;
                else    numPos2++;
                counter++;
            }
            for(int i=0;i<2;i++){
                if(numPos1<nums1.size()&&numPos2<nums2.size()){
                    if(nums1.at(numPos1)<nums2.at(numPos2))   {result+=nums1.at(numPos1);numPos1++;}
                    else    {result+=nums2.at(numPos2);numPos2++;}
                }
                else if(numPos1<nums1.size())  {result+=nums1.at(numPos1);numPos1++;}
                else    {result+=nums2.at(numPos2);numPos2++;}
            }
            result =result/2;
        }
        return result;
    }
};

5.总结

(1)上述代码不够优雅,原因是一开始就将奇偶分开处理,导致有很大程度的重复代码。

(2)这也说明了这个题的细节问题:即对奇偶元素个数的游标位置的处理细节。


原文地址:https://www.cnblogs.com/fangexuxiehuihuang/p/14504809.html