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

题目链接

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

题目分析

过了那么久,终于敢把这个题写一写了,其实在半年前看算法视频已经学过一次了,但是当时怎么都理解不了,现在自己又重新理解了一下。
题目给了两个正序数组,要求我们求其复合在一起的数组的中位数。
如果题目不限定条件的话,我们直接归并排序取中间即可,但是做不得,题目有如下要求

要求算法的时间复杂度为 O(log(m + n))。

看到log,那么大概率就是二分查找的内容了。这个题的二分比较抽象,我们先把两个数组长度和求出来,那么中位数分和为奇偶的情况,奇数就是第sum / 2 + 1位,如果是偶数的话就是第sum / 2和第sum / 2 + 1位之和的平均数。

那么问题到我们如何寻找这个第k位了,我们借用二分的思想,把这两个数组抽象成一个整体来做。
我们使用l1, l2去记录nums1和num2当前的起始位。
我们分别取两个数组当前长度的第k/2位,记作a,b。
如果a < b, 那么nums1中[l1, l1 + k/2)这些数据都比b小,所以说明我们寻找的第k位不可能存在这个区间,我们去nums1[l1 + k/2, nums1.length - 1]和nums2[l2, nums2.length - 1]这个位置找。
相反的话也是一样的。
我们还需要注意下一些终止条件。
如果k == 1的话,我们就取这两个数组的第一位的最小值返回即可。
如果数组的起始位置大于此数组的长度,那么我们只需要在另外一个数组寻找第k位即可。

代码实现

class Solution {
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
        int length1 = nums1.length;
        int length2 = nums2.length;
        int sum = length1 + length2;
        if((sum & 1) == 0){
            return (find(nums1, nums2, 0, 0, sum / 2) + find(nums1, nums2, 0, 0, (sum / 2) + 1)) / 2.0;
        }else{
            return find(nums1, nums2, 0, 0, (sum / 2) + 1);
        }
    }
    public double find(int[] nums1, int[] nums2, int l1, int l2, int k){
        if(l1 >= nums1.length){
            return nums2[l2 + k - 1];
        }
        if(l2 >= nums2.length){
            return nums1[l1 + k - 1];
        }
        if(k == 1){
            return Math.min(nums1[l1], nums2[l2]);
        }
        int midValue = (k/2 + l1 - 1>= nums1.length)?Integer.MAX_VALUE:nums1[k/2 + l1 - 1];
        int midValue2 = (k/2 + l2 - 1>= nums2.length)?Integer.MAX_VALUE:nums2[k/2 + l2 - 1];
        if(midValue > midValue2){
            return find(nums1, nums2, l1, l2 + k/2, k - k/2);
        }else{
            return find(nums1, nums2, l1 + k / 2, l2, k - k/2);
        }
    }
}
posted @ 2020-09-14 11:12  ZJPang  阅读(126)  评论(0编辑  收藏  举报