leetcode4 Median of Two Sorted Arrays

给出两个有序的数组,求其中位数,元素个数位偶数个,则求其上中位数和下中位数的平均数.

最简单粗暴的做法就是直接从两个数组的开头对比,建立两个指针遍历数组,时间为O(n+m).(数组1长度为n数组2长度为m)

如果想要log的时间复杂度就得使用二分了,如果是计算其中位数,序列中必然有(m+n)/2个数小于中位数mid,我们就根据这个公式就可以进行二分,我们先取数组1的中位数mid1,数组1中有n/2个数小于mid1,那么我们用它与数组2的第((m+n)/2-n/2+1)个数与其比较,这是就出现了两种情况,一种是大于,一种是小于,等于包含在哪边都可以.

其实这时候数组1和数组2都被分割成了两部分,下面也进入到了今天重点的位置.

如果大于则数组1的后半部分和数组2的前半部分就已经可能是中位数了,因为不符合中位数的公式.

同理如果小于,那么数组1的前半部分和数组2的后半部分就可以排除了.

这样我们就可以将其简化成了一个二分查找的情况.但是这道题有一定难度的地方就是整体序列为偶数个数的时候,我们需要求两个中位数将其相加并除2,但是如果这两个数每个数组占了一个,这就是一个难点.

这时候我们有两种思路,一种是先判断序列的元素个数,如果为奇数,直接求解中位数返回即可,如果为偶数那么就先求上中位数再求下中位数,将其相加除2再返回即可.

解法1:分别求上下中位数

class Solution {
public:
    double findMedianSortedArrays(int A[], int m, int B[], int n) {
        int mid_a = m/2, mid_b = n/2;
        if(m == 0)
        {
            if(n % 2 == 0)
                return (B[mid_b] + B[mid_b-1]) / 2.0;
            else return B[mid_b];
        }
        else if(n == 0)
        {
            if(m % 2 == 0)
                return (A[mid_a] + A[mid_a-1]) / 2.0;
            else return A[mid_a];
        }
        
        if((m+n) % 2)
            return helper_up(A, m, B, n);
        else return (helper_up(A, m, B, n) + helper_down(A, m, B, n)) / 2.0;
    }
    int helper_up(int A[], int m, int B[], int n)
    {
        int mid_a = m/2, mid_b = n/2;
        if(m == 1)
        {
            if(n == 1)
                return A[0] < B[0] ? B[0] : A[0];
            if(n % 2 == 0)
            {
                if(A[0] >= B[mid_b])
                    return B[mid_b];
                else if(A[0] <= B[mid_b-1])
                    return B[mid_b-1];
                else return A[0];
            }
            else
            {
                if(A[0] >= B[mid_b+1])
                    return B[mid_b+1];
                else if(A[0] <= B[mid_b])
                    return B[mid_b];
                else return A[0];
            }
        }
        else if(n == 1)
        {
            if(m % 2 == 0)
            {
                if(B[0] >= A[mid_a])
                    return A[mid_a];
                else if(B[0] <= A[mid_a-1])
                    return A[mid_a-1];
                else return B[0];
            }
            else
            {
                if(B[0] >= A[mid_a+1])
                    return A[mid_a+1];
                else if(B[0] <= A[mid_a])
                    return A[mid_a];
                else return B[0];
            }
        }
        else
        {
            int cutLen = mid_a > mid_b ? mid_b:mid_a;//注意每次减去短数组的一半,如果数组长度n是奇数,一半是指n-1/2
            if(A[mid_a] == B[mid_b])
                return A[mid_a];
            else if(A[mid_a] < B[mid_b])
                return helper_up(&A[cutLen], m - cutLen, B, n - cutLen);
            else return helper_up(A, m - cutLen, &B[cutLen], n-cutLen);
        }
    }
    
    int helper_down(int A[], int m, int B[], int n)
    {
        int mid_a = (m-1)/2, mid_b = (n-1)/2;
        if(m == 1)
        {
            if(n == 1)
                return A[0] < B[0] ? A[0] : B[0];
            if(n % 2 == 0)
            {
                if(A[0] >= B[mid_b+1])
                    return B[mid_b+1];
                else if(A[0] <= B[mid_b])
                    return B[mid_b];
                else return A[0];
            }
            else
            {
                if(A[0] >= B[mid_b])
                    return B[mid_b];
                else if(A[0] <= B[mid_b-1])
                    return B[mid_b-1];
                else return A[0];
            }
        }
        else if(n == 1)
        {
            if(m % 2 == 0)
            {
                if(B[0] >= A[mid_a+1])
                    return A[mid_a+1];
                else if(B[0] <= A[mid_a])
                    return A[mid_a];
                else return B[0];
            }
            else
            {
                if(B[0] >= A[mid_a])
                    return A[mid_a];
                else if(B[0] <= A[mid_a-1])
                    return A[mid_a-1];
                else return B[0];
            }
        }
        else
        {
            int cutLen = (m/2 > n/2 ? n/2:m/2);//注意每次减去短数组的一半,如果数组长度n是奇数,一半是指n-1/2
            if(A[mid_a] == B[mid_b])
                return A[mid_a];
            else if(A[mid_a] < B[mid_b])
                return helper_down(&A[cutLen], m - cutLen, B, n - cutLen);
            else return helper_down(A, m - cutLen, &B[cutLen], n-cutLen);
        }
    }
};


如果我们进一步抽象一下就可以得出一个更加通用的算法,那就是求解两个有序数组的第K大数,这样这个算法就更加通用,其实思想是一样的只不过我们上面的算法中的k是固定的.


解法2:求解第K大数函数求解 python

class Solution:
    # @return a float
    def findMedianSortedArrays(self, A, B):
        l=len(A)+len(B)
        return self.findKth(A,B,l//2) if l%2==1 else (self.findKth(A,B,l//2-1)+self.findKth(A,B,l//2))/2.0


    def findKth(self,A,B,k):
        
        if len(A)>len(B):#确保A长度为最小的那一个,如果其中一个为空,就直接反悔另外一个的第K个数
            A,B=B,A
        if not A:
            return B[k]

        if k==len(A)+len(B)-1:#要求的是第K大的数,如果两个数组长度加起来为k,那么只需比较最后一个元素就可得出结果.
            return max(A[-1],B[-1])
        
        i=len(A)//2#取A数组的下中位数
        j=k-i#取B的第k-i+1个数

        if A[i]>B[j]:
            return self.findKth(A[:i],B[j:],i)
            #去掉不符合的两个部分,k变成i是因为整个序列最小的k-i个数已经被去掉了,k=k-(k-i)=i
        else:
            return self.findKth(A[i:],B[:j],j)
            #去掉不符合的两个部分,k变成j是因为整个序列最小的i个数已经被去掉了,k=k-i


解法2:求解第K大数函数求解 C++

class Solution {
public:
    double findMedianSortedArrays(int A[], int m, int B[], int n) {
        int mid_a = m/2, mid_b = n/2;
        if(m == 0)
        {
            if(n % 2 == 0)
                return (B[mid_b] + B[mid_b-1]) / 2.0;
            else return B[mid_b];
        }
        else if(n == 0)
        {
            if(m % 2 == 0)
                return (A[mid_a] + A[mid_a-1]) / 2.0;
            else return A[mid_a];
        }
        
        if((m+n) % 2)
            return findKthSmallest(A, m, B, n, (m+n+1)/2);
        else return (findKthSmallest(A, m, B, n, (m+n)/2) + findKthSmallest(A, m, B, n, (m+n)/2+1)) / 2.0;
    }
    //找到两个有序数组中第k小的数,k>=1
    int findKthSmallest(int vec1[], int n1, int vec2[], int n2, int k)
    {
        //边界条件处理
        if(n1 == 0)return vec2[k-1];
        else if(n2 == 0)return vec1[k-1];
        if(k == 1)return vec1[0] < vec2[0] ? vec1[0] : vec2[0];
        
        int idx1 = n1*1.0 / (n1 + n2) * (k - 1);
        int idx2 = k - idx1 - 2;
     
        if(vec1[idx1] == vec2[idx2])
            return vec1[idx1];
        else if(vec1[idx1] < vec2[idx2])
            return findKthSmallest(&vec1[idx1+1], n1-idx1-1, vec2, idx2+1, k-idx1-1);
        else
            return findKthSmallest(vec1, idx1+1, &vec2[idx2+1], n2-idx2-1, k-idx2-1);
    }
};



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值