【LeetCode题解】4.寻找两个正序数组的中位数

题目说明

给定两个大小为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。
请你找出这两个正序数组的中位数,并且要求算法的时间复杂度为 O(log(m + n))。
你可以假设 nums1 和 nums2 不会同时为空。

示例 1:
nums1 = [1, 3]
nums2 = [2]
则中位数是 2.0
示例 2:
nums1 = [1, 2]
nums2 = [3, 4]
则中位数是 (2 + 3)/2 = 2.5

解题思路

计算出两个数组的中位值k,k 位置的值就是中位数。
只要找到中位值k 就可以得出中位数了。

首先我们要理解中位值如何得出:

  • 当数组个数为奇数值时:k = (k + 1) / 2;
  • 当数组个数为偶数时,k 有两个:k_1 = k / 2, K_2 = k / 2 + 1;

那么中位数为:

  • 奇数:k 的值;
  • 偶数:(k_1 + k_2) / 2.0;

如何得出两个数组中的中位值:
因为数组是有序数组,所以通过不断的将数组分成两份,排除掉小的那份,逐渐向中位值靠拢。

  • num1 数组先被排除完,此时中位值在num2 中,返回此时数组中的k 值;
  • num2 数组先被排除完,此时中位值在num1 中,返回此时数组中的k 值;
  • 找到k 值,返回两个数组中此时的首元素的最小值。
    index 偏移量用来重新定义数组的首元素,而k 值则是当前数组的中位值。

若当前没有匹配到合适的中位值,则将k 值减去删除的元素数量,增加删除数组的偏移量。

// 给出其中较小值
int min(int num1, int num2){
    
    
    if(num1 <= num2)
        return num1;
    else
        return num2;
}

// 得出中位值k 的值
double findMedianElement(int* nums1, int nums1Size, int* nums2, int nums2Size, int k){
    
    
    int index1 = 0, index2 = 0; // 用来记录nums1 和 nums2 数组的偏移量

    while(true){
    
     // 除非符合条件,否则无限循环
        /* 边界情况 */
        // nums1 或nums2 为空数组或者刚好排除完时,直接返回另一个数组的中位值
        if(index1 == nums1Size)
            return nums2[index2 + k - 1];
        if(index2 == nums2Size)
            return nums1[index1 + k - 1];
        // k == 1 时,找到中位值,返回中位值的值。    
        if(k == 1)
            return min(nums1[index1], nums2[index2]);
        
        /* 正常情况 */
        // 通过不断的二分来排除掉较小的数组,直到找到中位值为止
        // 若超出数组边界,则将数组最后一位位置赋值给newIndex
        // 否则newIndex = 偏移量 + 中位值的中位值
        int newIndex1 = min(index1 + k / 2 - 1, nums1Size - 1);
        int newIndex2 = min(index2 + k / 2 - 1, nums2Size - 1);
        // 将当前中位值的值提出
        int pivot1 = nums1[newIndex1];
        int pivot2 = nums2[newIndex2];

        // 对比中位值,将较小的值的偏移量增加,中位值k 减去删除的个数。
        if(pivot1 <= pivot2){
    
    
            k -= newIndex1 - index1 + 1;
            index1 = newIndex1 + 1;
        }
        else{
    
    
            k -= newIndex2 - index2 + 1;
            index2 = newIndex2 + 1;
        }
        
    }
}

double findMedianSortedArrays(int* nums1, int nums1Size, int* nums2, int nums2Size){
    
    
    int k = nums1Size + nums2Size;
    // 若总数为奇数,直接提出中位数
    if(k % 2 == 1)
        return findMedianElement(nums1, nums1Size, nums2, nums2Size, (k + 1) / 2);
    // 若总数为偶数,找出两个中位值,中位数为两数平均值    
    else
        return (findMedianElement(nums1, nums1Size, nums2, nums2Size, k / 2) + findMedianElement(nums1, nums1Size, nums2, nums2Size, k / 2 + 1)) / 2.0;
}

猜你喜欢

转载自blog.csdn.net/weixin_43776724/article/details/108690748