leetcode4:两个有序数组的中位数

题目描述

给定两个有序数组nums1和nums2,请找出这两个数组的中位数。

解题思路

暴力法

最简单直观的方法是先将两个数组合并成一个有序数组,然后直接根据合并后数组的长度是奇数还是偶数来找到中位数,这种方法的时间复杂度为O(m+n)。

二分查找法

为了满足时间复杂度的要求,可以采用二分查找的思想。主要思路是将问题转化为在两个有序数组中寻找第k小的数,其中k为(m+n)/2(当数组总长度为奇数时)或(m+n)/2和(m+n)/2+1(当数组总长度为偶数时,需要找两个数来求平均值)。

具体步骤如下:

  • 初始化:设定两个指针left_1和left_2分别指向nums1和nums2的起始位置,以及k的初始值为(m+n)/2(或(m+n)/2+1,根据总长度是奇数还是偶数决定)。
  • 比较和移动指针:
    比较nums1[left_1 + k/2 - 1](注意下标不要越界)和nums2[left_2 + k/2 - 1]的值:
    • 如果前者较小,则说明nums1[left_1:left_1+k/2]中的元素都小于第k小的数,因此可以将这部分元素排除,将left_1增加k/2,k减去k/2(因为已经排除了这么多元素)。
    • 同理,如果后者较小或两者相等,则排除nums2中的相应元素。
  • 边界情况处理:
    • 如果某个数组被完全排除(即left_1或left_2超出数组长度),则直接返回另一个数组中第k-1个位置的元素(因为此时已经确定了前k-1小的元素都在剩下的数组中)。
    • 如果k变为1,则返回两个数组中当前left_1和left_2指向的元素中较小的一个。
  • 递归或循环:重复上述步骤,直到找到第k小的数。
  • 计算中位数:
    • 如果数组总长度为奇数,则第k小的数就是中位数。
    • 如果数组总长度为偶数,则需要找到第(m+n)/2和第(m+n)/2+1小的数,然后求它们的平均值。

代码示例

var findMedianSortedArrays = function(nums1, nums2) {  
    // 确保nums1是较短的数组  
    if (nums1.length > nums2.length) {  
        [nums1, nums2] = [nums2, nums1];  
    }  
  
    const m = nums1.length;  
    const n = nums2.length;  
  
    // 二分查找的左右边界  
    let left = 0, right = m;  
    let halfLen = Math.floor((m + n + 1) / 2);  
  
    while (left <= right) {  
        const i = Math.floor((left + right) / 2);  
        const j = halfLen - i;  
  
        const nums1LeftMax = (i === 0) ? -Infinity : nums1[i - 1];  
        const nums1RightMin = (i === m) ? Infinity : nums1[i];  
  
        const nums2LeftMax = (j === 0) ? -Infinity : nums2[j - 1];  
        const nums2RightMin = (j === n) ? Infinity : nums2[j];  
  
        if (nums1LeftMax <= nums2RightMin && nums2LeftMax <= nums1RightMin) {  
            // 当总长度是奇数时,直接返回两个右边界中的较小值  
            if ((m + n) % 2 === 1) {  
                return Math.max(nums1LeftMax, nums2LeftMax);  
            }  
            // 当总长度是偶数时,返回两个左右边界值的平均值  
            return (Math.max(nums1LeftMax, nums2LeftMax) + Math.min(nums1RightMin, nums2RightMin)) / 2;  
        } else if (nums1LeftMax > nums2RightMin) {  
            // nums1的分割点需要向左移动  
            right = i - 1;  
        } else {  
            // nums1的分割点需要向右移动  
            left = i + 1;  
        }  
    }  
  
    // 如果没有找到有效的分割(理论上不应该发生)  
    throw new Error('No valid median found');  
};
  • 5
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值