LeetCode:4. Median of Two Sorted Arrays

题目:

There are two sorted arrays nums1 and nums2 of size m and n
respectively.

Find the median of the two sorted arrays. The overall run time
complexity should be O(log (m+n)).

You may assume nums1 and nums2 cannot be both empty.

Example 1:

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

The median is 2.0 Example 2:

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

The median is (2 + 3)/2 = 2.5

题目是找出两个有序数组的中位数。
解法来源:
https://leetcode.com/problems/median-of-two-sorted-arrays/discuss/2481/Share-my-O(log(min(mn))-solution-with-explanation?page=15
此题的解法请去看原解答,十分清晰。我这里记录下来的只是我自己看解答过程中的一个小困惑的一些想法,这里没有涉及此题的解法。

其实这题很容易就想到的是先归并排序,然后找中位数。但是如果用归并排序的话时间复杂度是O(m+n),不符合题目要求。

这题有一个很烦人,很让人困惑但是绕不过去的点,即关于用一个有序数组的哪个索引来表示中位数:
我们规定,该索引将数组分为左右两部分,而且该索引指向的那个位置属于右边的那部分。如果数组长度为偶数,那么左右两部分长度相等;如果数组长度为奇数,那么左边长度比右边长度多一。所以如何计算该索引呢?答案是(len+1)/2。
比如长度为4,(4+1)/2=2,0到1是左边,2到3是右边,左右长度相等,2属于右边。
比如长度为5,(5+1)/2=3,0到2是左边,3到4是右边,左边比右边长1,3属于右边。
以后遇到类似的题目都遵循这个规定会简化思考的负担。

整个解法的大致思路是:
假设数组A和B的长度分别为m和n。取0<=i<=m, 0<=j<=n,A[0]到A[i-1]和B[0]到B[j-1]属于较小的一半,A[i]到A[m-1]和B[j]到B[n-1]属于较大的另一半,要使得两边的数目相等或者相差1,要满足以下两个条件:
1.i + j = m - i + n - j + 1
2.A[i-1] <= B[j] && B[j-1] <= A[i]
这里如果n >= m,可将条件一化为j = (m+n+1)/2-i,否则j可能为负。所以如果m < n的话,需要在代码开头将他们swap。至于这里的+1,就是因为上面所说的计算中位数的索引。
还有需要考虑边界条件,也就是比如i = 0的时候,不能取A[i-1],这里不谈。
整个代码的过程就是需要取i,然后根据i计算出j,然后看看符不符合第二个条件。如果符合,则说明找到合适的;如果没有,根据大小关系,调整i的大小,再往复循环。

做这个题目的一个收获就是学习了这个算法,还有一个就是这样一个思想:如果有两个变量,而且有一个不等式,一个等式,可以用等式来将一个变量表示为另一个变量,然后用不等式来验证是否正确。

下面是代码:

class Solution {
public:
    double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
        if (nums2.size() < nums1.size())
            nums1.swap(nums2);
        
        int sz1 = nums1.size(), sz2 = nums2.size();
        int lo = 0, hi = sz1-1;
        int i, j;
        while (1) {//!!!!!!!!!!!不能是lo <= hi,至于为什么:我猜测:lo <= hi是因为一般二分查找,需要在范围内;但是这里的i,j可以指向边界的下一位,即可以越界,所以不能是lo <= hi
            i = lo + (hi - lo) / 2;
            j = (sz1 + sz2 + 1) / 2 - i; //!!!!!!!(len + 1) / 2
            if (i > 0 && j < sz2 && nums1[i-1] > nums2[j]) {
                hi = i - 1;
            }
            else if (j > 0 && i < sz1 && nums1[i] < nums2[j-1]) {
                lo = i + 1;
            }
            else {
                int leftMax;
                if (i == 0) leftMax = nums2[j-1];
                else if (j == 0) leftMax = nums1[i-1];
                else leftMax = max(nums1[i-1], nums2[j-1]);
                if ((sz1 + sz2) % 2 == 1)
                    return leftMax;
                
                int rightMin;
                if (i == sz1) rightMin = nums2[j];
                else if (j == sz2) rightMin = nums1[i];
                else rightMin = min(nums2[j], nums1[i]);
                
                return ((double)leftMax + (double)rightMin) / 2.0;
            }
        }
        return 0.0;
    }
};
posted @ 2018-11-20 10:35  于老师的父亲王老爷子  阅读(11)  评论(0)    收藏  举报