【算法设计与分析作业题】第七周:4. Median of Two Sorted Arrays

题目

C++ solution

class Solution {
public:
    double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
        int m = nums1.size();
        int n = nums2.size();
        if (m <= n)
        {
        	return find(m, n, nums1, nums2);
        } else {
            return find(n, m, nums2, nums1);
        }
        
    }
    double find(int m, int n, vector<int>& nums1, vector<int>& nums2) {
        int iMin = 0, iMax = m, midPos = (m + n +1) / 2;
        while (iMin <= iMax) {
            int i = (iMin + iMax) / 2;
            int j = midPos - i;
            if (i < iMax && nums2[j - 1] > nums1[i]) // i is too small
            {
                iMin = i + 1;
            }
            else if (i > iMin && nums1[i - 1] > nums2[j]) // i is too big
            {
                iMax = i - 1;
            }
            else
            {
                int maxLeft = 0;
                if (i == 0) maxLeft = nums2[j -1];
                else if (j == 0) maxLeft = nums1[i - 1];
                else maxLeft = nums2[j - 1] > nums1[i - 1] ? nums2[j - 1] : nums1[i - 1];
                if ((m + n) % 2 == 1) return maxLeft;

                int minRight = 0;
                if (i == m) minRight = nums2[j];
                else if (j == n) minRight = nums1[i];
                else minRight = nums2[j] < nums1[i] ? nums2[j] : nums1[i];
                return (maxLeft + minRight) / 2.0;
            }
        }
        return 0.0;
    }
};

简要题解

中位数(median):将集合中的数进行排序,最中间的那个数或两个数的平均数即是中位数。
题中两个有序数组(长度分别为m, n),将所有数以中位数分割为左半部分(left_part)和右半部分(right_part)

left_part right_part
nums1[0], nums1[1], … , nums1[i-1] nums1[i], nums1[i+1], … , nums1[m-1]
nums2[0], nums2[1], … , nums2[j-1] nums2[i], nums2[i+1], … , nums2[n-1]

其中

i = 0 ~ m, j = 0 ~ n
len(left_part) = len(right_part)
max(left_part) <= min(right_part)
median = (max(left_part) + min(right_part)) / 2 (m+n为偶数) 
median = max(left_part) (m+n为奇数)

由上性质,可得

i + j = m - i + n - j (or: m - i + n - j + 1)
即 i = 0 ~ m, j = (m + n + 1) / 2 - i;(由于整数除运算舍去小数部分,两种情况可以合一)
注意:为保证 j 不为负,必须 m <=  n;若 m > n,只需互换,计算完全相同
nums2[j-1] <= nums1[i],nums1[i-1] <= nums2[j]

考虑特殊情况
当 i = 0, i = m, j = 0, j = m,即意味着 nums1[i-1], nums1[i], nums2[j-1], nums2[j] 可能不存在。解决办法很简单,把相应的限制条件(nums2[j-1] <= nums1[i] 或 nums1[i-1] <= nums2[j])忽略即可。

通过以上分析,可以总结出每次搜索只有三种情况
注意:j 的值随 i的变化而变化,所以仅需考虑 i 如何改变来得出结果。且 i < m,则 j > 0;i > 0,则 j < n。

// 1. i 取值较小,需增大
i < m && nums2[j-1] > nums1[i]

// 2. i 取值较大, 需减小
i > 0 && nums1[i-1] > nums2[j]

// 3. i 取值刚好,结束搜索,计算结果并返回
( j == 0 || i == m || nums2[j-1] <= nums1[i]) && (i == 0 || j == n || nums1[i-1] <= nums2[j])

采用二分搜索,即可搜索得到 i 的目标值,由 i 值计算得到 j 值,再计算除两个数组的中位数,得到答案。

猜你喜欢

转载自blog.csdn.net/For_course/article/details/83063866
今日推荐