【刷题日记】leetcode4-寻找两个正序数组的中位数

84 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第6天,点击查看活动详情

题目描述

image.png

题目释义

  • 给定数组nums1和nums2
  • 求这两个数组的中位数 题目要求算法时间复杂度为O(log (m+n))

解题思路

数组的中位数,最简单的方法是将两个数组进行合并,然后再进行排序,然后再取中位数。但是通过这种方法解题,算法时间复杂度为O (m+n)不满足条件。 求数组的中位数:

  • 如果数组大小为奇数,则中位数的排序为(length+1)/2;
  • 如果数组大小为偶数,则中位数的排序为(length/2+length/2+1)/2 总的来说数组大小为奇数,需要获取的是排序为(length+1)/2的值;如果为偶数,则需要获取排序为length/2和length/2+1的值。

求数组的指定排序位置的数值,而且要使时间复杂度为O(log (m+n)),就应该想到用二分法解题。 二分值应该是需要求的排序数,假设这个值为k,则第一次先查询两个数组位置为k/2的值,比较它们的大小,如果nums1[k/2]>nums2[k/2],则数组2的查询范围缩小,即nums2前面的数一定不满足中位数的条件。依次类推,截止条件应该为其中一个数组到数组尾端(根据当前k和已排除了的数组长度获得中位数值)或k==1即找到中位数位置直接返回。

代码实现:

public  double findMedianSortedArrays(int[] nums1, int[] nums2) {
    int n = nums1.length;
    int m = nums2.length;
    double res;
    if ((m + n ) % 2 == 0){
        //偶数
        res = (getKth(nums1,0,n-1,nums2,0,m-1,(m+n)/2)+getKth(nums1,0,n-1,nums2,0,m-1,(m+n)/2+1))*0.5;
    }else {
        //奇数
        res = getKth(nums1,0,n-1,nums2,0,m-1,(m+n+1)/2);
    }
    return res;
}

private int getKth(int[] nums1, int start1, int end1, int[] nums2, int start2, int end2, int k) {
    //交换数组位置,让长数组始终位于第二位
    if (end1-start1 > end2-start2){
        return getKth(nums2, start2, end2, nums1, start1, end1, k);
    }
    //如果短数组到尾端,则直接返回长数组的位置
    if (end1<start1){
        return nums2[start2 + k - 1];
    }
    //如果k达到1,说明已经找到二分点
    if (k == 1){
        return Math.min(nums1[start1], nums2[start2]);
    }
    int i = start1 + Math.min(end1-start1+1, k / 2) - 1;
    int j = start2 + Math.min(end2-start2+1, k / 2) - 1;
    if (nums1[i] > nums2[j]) {
        //第一个数组的值大于第二个数组,则直接将第二个数组的前移
        return getKth(nums1, start1, end1, nums2, j + 1, end2, k - (j - start2 + 1));
    }
    else {
        //第二个数组的值大于第一个数组,则直接将第一个数组的前移
        return getKth(nums1, i + 1, end1, nums2, start2, end2, k - (i - start1 + 1));
    }
}