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

思路一 归并排序

此题是两个有序数组中查找第K小的数的特例,而我能想到的查找第K个元素便是使用归并排序算法(邓公的<<数据结构>>讲的非常不错)。所以,一开始我是按照归并排序的思路+第K个元素停止的来做的。但一开始我没想到可以把整个查找函数提取出来进行封装,当时写的有点复杂。
在查看一些解题思路后,得到启发,把查找函数提出来后,代码易读性与简洁性得到了很大的提升。
关于时间复杂度,题目要求O(log(n+m)),但此思路的时间复杂度为O(n+m),一般情况下的时间复杂度默认最坏时间复杂度。因此在时间复杂度的要求上,这个思路是不满足的。但从提交的结果来看,算法实际消耗的时间还是可以令人满足的。

代码

class Solution {
public:
    double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
        int xSize=nums1.size();
        int ySize=nums2.size();
        int total = xSize+ySize;
        if((xSize+ySize)&0x01) return find_Kth(nums1,xSize,nums2,ySize,total/2+1);
        else return (find_Kth(nums1,xSize,nums2,ySize,total/2)+find_Kth(nums1,xSize,nums2,ySize,total/2+1))/2;
    }
private:
    double find_Kth(vector<int>& nums1,int xSize,vector<int>& nums2,int ySize,int target){
        int xIndex=0;
        int yIndex=0;
        int loken=0;
        double value;
        while(xIndex<xSize||yIndex<ySize){
            if((xIndex<xSize)&&(!(yIndex<ySize)||nums1[xIndex]<=nums2[yIndex])){
                value=nums1[xIndex];
                xIndex++;
                loken++;
                if(loken==target) return value;
            }
            if((yIndex<ySize)&&(!(xIndex<xSize)||(nums2[yIndex]<nums1[xIndex]))){
                value=nums2[yIndex];
                yIndex++;
                loken++;
                if(loken==target) return value;
            }
        }
        return 0;
    }
};

结果

Leetcode 4.寻找两个有序数组的中位数_第1张图片

思路二

设定ia,ib。其中ia、ib满足一下条件:

  • m
  • ib+ia=k,ib=k-ia
    ia指示的是A中前ia个元素,ib指示的是B中前ib个元素。

当A[ia]=B[ib]时,因为ia+ib=k,所以第k个元素=A[ia]=B[ib],返回A[ia]或B[ib];
当A[ia]

这个算法的思路实现并不算难,但是难就难在了边界条件的确定。目前对于这一块,我并没有很深入的理解,可能需要一定的题量支持。就对三个边界发生的情况做下解释:

  • 第一个是说,A的范围必须比B的范围小。因为ia取值时,考虑了A的范围,但是B取值时,并没有考虑。
  • 第二个是说,A为空,但A为空有两种可能,一种是输入时就是空的,另一种是,在执行过程中,A的范围不断变小而发生的。
  • 第三个是说,k=1。这个也是有两种,与上述情况类似。

代码

class Solution {
public:
    double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
        const int m=nums1.size();
        const int n=nums2.size();
        int total=m+n;
        if(total&0x01)
            return find_Kth(nums1.begin(),m,nums2.begin(),n,total/2+1);
        else 
            return (find_Kth(nums1.begin(),m,nums2.begin(),n,total/2+1)+find_Kth(nums1.begin(),m,nums2.begin(),n,total/2))/2;
    }
private:
    double find_Kth(vector<int>::const_iterator A,int m,vector<int>::const_iterator B,int n,int k){
        if(m>n) return find_Kth(B,n,A,m,k);
        if(m==0) return *(B+k-1);
        if(k==1) return min(*A,*B);

        int ia=min(k/2,m);
        int ib=k-ia;
        if(*(A+ia-1)<*(B+ib-1)) return find_Kth(A+ia,m-ia,B,n,k-ia);
        else if(*(B+ib-1)<*(A+ia-1)) return find_Kth(A,m,B+ib,n-ib,k-ib);
        else return A[ia-1];
    }
};

结果

Leetcode 4.寻找两个有序数组的中位数_第2张图片

参考资源

Leetcode 题解
Leetcode

你可能感兴趣的:(LeetCode)