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好处就在于省的你想哪里做不到了,人家想到的肯定比你全。因此在上面刷题能锻炼自己。

 

思路:这道题难在给你限时,也就是时间复杂度要求为o(log(m+n)),答案给的太复杂,也太详细,我看不下去数学推论过程。如果不限时,很简单:将两个数组合并成一个数组,然后利用sort排序,取中位数即可。时间复杂度超出。因为sort函数的时间复杂度难以计算(sort融合了多种排序的优势,因此不同数据量速度不同),这里就不给时间复杂度的计算问题了。

还有一种思路,就是在构成新的数组的同时排好序,有点像二叉搜索树,但是这里没用树算法,直接进行比较,然后将数据存入相应的数组内部。时间复杂度是o(m+n)

当然,这种思路可以继续根据题意优化,笔者的代码也是如此写的:添加一个计数器count,当 i 和 j 之和超过原来两个数组数据量的一半,就可以停止继续比较,得出答案即可。时间复杂度是o((m+n)/2)······其实还是没做到o(log(m+n))

class Solution {
public:
    double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
        int n = nums1.size();
        int m = nums2.size();
        int sum = n + m;
        int i = 0 , j = 0;
        int count = 0;
        vector<int> num;
        double result = 0;
        if(n!=0 && m!=0)
        {
            if(sum%2 == 0)
            {
                sum = sum/2;
                while(i+j<sum)
                {
                    if(i<n && j<m)
                    {
                        if(nums1[i] < nums2[j])
                            num.push_back(nums1[i++]);
                        else 
                           num.push_back(nums2[j++]);
                    }
                    else if(i<n && j>=m)
                        num.push_back(nums1[i++]);
                    else if(i>=n && j<m)
                        num.push_back(nums2[j++]);
                    count++;
                }
                if(i<n && j<m)
                {
                    if(nums1[i] < nums2[j])
                        num.push_back(nums1[i++]);
                    else
                        num.push_back(nums2[j++]);
                }
                else if(i<n)
                    num.push_back(nums1[i++]);
                else if(j<m)
                    num.push_back(nums2[j++]);
                result = (num[count-1] + num[count])/2.0;
            }
            else{
                sum = sum/2;
                while(i+j < sum)
                {
                    if(i<n && j<m)
                    {
                        if(nums1[i] < nums2[j])
                            num.push_back(nums1[i++]);
                        else 
                           num.push_back(nums2[j++]);
                    }
                    else if(i<n && j>=m)
                        num.push_back(nums1[i++]);
                    else if(i>=n && j<m)
                        num.push_back(nums2[j++]);
                    count++;
                }
                 if(i<n && j<m)
                {
                    if(nums1[i] < nums2[j])
                        num.push_back(nums1[i++]);
                    else
                        num.push_back(nums2[j++]);
                }
                else if(i<n)
                    num.push_back(nums1[i++]);
                else if(j<m)
                    num.push_back(nums2[j++]);  
                result = num[count];
            }
        }
        else if(n == 0)
        {
            
            if(m%2 != 0)
                result = nums2[m/2];
            else
                result = (nums2[m/2-1] + nums2[m/2])/2.0;
        }
        else if(m == 0)
        {
            if(n%2 != 0)
                result = nums1[n/2];
            else
                result = (nums1[n/2-1] + nums1[n/2])/2.0;
        }
        return result;
    }
};

我承认我的代码仍有继续优化的空间,例如不用将数据存在新建的vector数组中,从而节省空间开销;也可以减少if-else的使用来增加程序的可读性·········但是我已经被胜利冲昏了头脑,不想再写了,等到我二刷 leetcode 的时候,再看看有没有什么其他更好的算法吧!!

 


附上答案: 

class Solution {
    public double findMedianSortedArrays(int[] A, int[] B) {
        int m = A.length;
        int n = B.length;
        if (m > n) { // to ensure m<=n
            int[] temp = A; A = B; B = temp;
            int tmp = m; m = n; n = tmp;
        }
        int iMin = 0, iMax = m, halfLen = (m + n + 1) / 2;
        while (iMin <= iMax) {
            int i = (iMin + iMax) / 2;
            int j = halfLen - i;
            if (i < iMax && B[j-1] > A[i]){
                iMin = i + 1; // i is too small
            }
            else if (i > iMin && A[i-1] > B[j]) {
                iMax = i - 1; // i is too big
            }
            else { // i is perfect
                int maxLeft = 0;
                if (i == 0) { maxLeft = B[j-1]; }
                else if (j == 0) { maxLeft = A[i-1]; }
                else { maxLeft = Math.max(A[i-1], B[j-1]); }
                if ( (m + n) % 2 == 1 ) { return maxLeft; }

                int minRight = 0;
                if (i == m) { minRight = B[j]; }
                else if (j == n) { minRight = A[i]; }
                else { minRight = Math.min(B[j], A[i]); }

                return (maxLeft + minRight) / 2.0;
            }
        }
        return 0.0;
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值