leetcode:4.寻找两个正序数组的中位数

4. 寻找两个正序数组的中位数

leetcode:4.寻找两个正序数组的中位数_第1张图片

这个题可以就用最普通的合并两个数组或者双指针来做,不过这样做时间复杂度为O(m + n),达不到题目要求的log。所以只有利用二分查找的思路来做。

我们要找中位数,假设中位数是两个数组合并后的第k个数(我们这里说的第k是从下标为1数着走的),其实我们要找的就是两个数组中第k小的数,对于数组总长为偶数的两个数组,要找的就是第k小和第k+1小的数。所以现在问题转变为找两个正序数组中第k小的数了。

比较两个数组k/2的位置(即A[k/2-1]和B[k/2-1]),如果A[k/2-1] < B[k/2-1],则说明对于A[k/2-1],最多只有(k/2 - 1 + k/2 - 1 = k - 2)个元素比它小(因为A[k/2-1]和B[k/2-1]前面都有k/2 - 1个元素),所以对于A[k/2 - 1]最多只是第k - 1小的数,至于A[k/2 - 1]前面的数,更不可能是第k小的数了,所以包含A[k/2-1]在内的k/2个数都不可能是第k小的数,可以舍弃。舍弃之后我们更新k的值,因为现在我们要找的是新的A的数组和B数组加起来第k小的值了,而前面k/2个数已经找到了,所以k = k - k/2;同样的,如果A[k/2-1] >= B[k/2-1]是一样的道理。

注意下面三种情况:

  • 如果 A[k/2-1]或者B[k/2-1] 越界,那么我们可以选取对应数组中的最后一个元素。在这种情况下,我们必须根据排除数的个数减少 k 的值,而不能直接将 k 减去k/2(即我们每次减掉的是我们排除的值而不是固定的k/2)。

  • 如果一个数组为空,说明该数组中的所有元素都被排除,我们可以直接返回另一个数组中第 k 小的元素。

  • 如果k=1,我们只要返回两个数组首元素的最小值即可。

代码如下:

class Solution {
private:
    int findKMinNum(vector<int>& nums1, vector<int>& nums2, int k) {
        int m = nums1.size(), n = nums2.size();
        int index1 = 0, index2 = 0;
        while (true) {
            if (index1 == m) {
                return nums2[index2 + k - 1];
            }
            if (index2 == n) {
                return nums1[index1 + k - 1];
            }
            if (k == 1) {
                return min(nums1[index1], nums2[index2]);
            }
            int new_index1 = min(index1 + k / 2 - 1, m - 1);
            int new_index2 = min(index2 + k / 2 - 1, n - 1);
            int pivot1 = nums1[new_index1];
            int pivot2 = nums2[new_index2];
            if (pivot1 < pivot2) {
                k -= new_index1 - index1 + 1;
                index1 = new_index1 + 1;
            }
            else {
                k -= new_index2 - index2 + 1;
                index2 = new_index2 + 1;
            }
        }
    }
public:
    double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
        int sum = nums1.size() + nums2.size();
        if (sum % 2 == 1) {
            return findKMinNum(nums1, nums2, (sum + 1) / 2);
        }
        else {
            return (findKMinNum(nums1, nums2, sum / 2) + findKMinNum(nums1, nums2, sum / 2 +1)) / 2.00;
        }
    }
};

你可能感兴趣的:(LeetCode刷题笔记,leetcode,算法,数据结构,二分查找)