【重点!!!】【二分查找】4.寻找两个正序数组的中位数

题目

法1:二分查找(最优解法)

时间复杂度:O(logMin(m, n)),空间复杂度:O(1)。
同时看这两种解法及其注释!!!
视频讲解:https://www.bilibili.com/video/BV1Xv411z76J/?spm_id_from=333.337.search-card.all.click&vd_source=af30aa36f473ad5a8ffdcc06e213d1f6
在这里插入图片描述

Python

class Solution:
    def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:
        if len(nums1) > len(nums2):
            nums1, nums2 = nums2, nums1
        m, n = len(nums1), len(nums2)
        total = (m + n + 1) // 2
        # 在nums1的区间[0, m]里查找恰当的分割线
        # 使得nums1[i - 1] ≤ nums2[j] && nums2[j - 1] ≤ nums1[i]
        left, right = 0, m # [a, b)开闭区间
        while left < right:
            nums1_left = (left + right + 1) // 2        # nums1分割线左边元素数量
            nums2_left = total - nums1_left             # nums2分割线左边元素数量
            if nums1[nums1_left-1] > nums2[nums2_left]: # 分割线太靠右了,需要往左移动
                right = nums1_left-1
            else:
                left = nums1_left
        i, j = left, total - left
        nums1_left_max = -inf if i == 0 else nums1[i-1]
        nums1_right_min = inf if i == m else nums1[i]
        nums2_left_max = -inf if j == 0 else nums2[j-1]
        nums2_right_min = inf if j == n else nums2[j]
        if (m + n) % 2 == 1:
            return max(nums1_left_max, nums2_left_max)
        else:
            return (max(nums1_left_max, nums2_left_max) + min(nums1_right_min, nums2_right_min)) / 2.0

Java

class Solution {
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
        if (nums1.length > nums2.length) {
            int[] tmp = nums1;
            nums1 = nums2;
            nums2 = tmp;
        }
        int m = nums1.length, n = nums2.length;
        // 在nums1的区间[0, m]里查找恰当的分割线
        // 使得nums1[i - 1] ≤ nums2[j] && nums2[j - 1] ≤ nums1[i]

        int totalLeft = (m + n + 1) / 2; // 左 ≥ 右
        int left = 0, right = m; // [left, right)是闭开区间
        while (left < right) {
            int nums1Left = (left + right + 1) / 2; // 是指的nums1分割线左侧元素个数(左 ≥ 右), 对应索引是nums1Left - 1
            int nums2Left = totalLeft - nums1Left;  // 是指的nums2分割线左侧元素个数(左 ≥ 右), 对应索引是nums2Left - 1
            if (nums1[nums1Left - 1] > nums2[nums2Left]) { // nums1的分割线太靠右,需要往左移
                right = nums1Left - 1; // right是取不到的边界, 下次迭代索引nums1Left - 1肯定取不到,故设置right = nums1Left - 1
            } else { // 这里并未直接判断nums2[nums2Left - 1]与nums1[nums1Left]的关系, 故使得nums1[nums1Left]尽量大
                left = nums1Left;      // left是可取到的边界,  下次迭代索引可能取到nums1Left,故设置left = nums1Left
            }
        }
        int i = left, j = totalLeft - left;
        int nums1LeftMax = i == 0 ? Integer.MIN_VALUE : nums1[i - 1];
        int nums1RightMin = i == m ? Integer.MAX_VALUE : nums1[i];
        int nums2LeftMax = j == 0 ? Integer.MIN_VALUE : nums2[j - 1];
        int nums2RightMin = j == n ? Integer.MAX_VALUE : nums2[j];
        int leftMax = Math.max(nums1LeftMax, nums2LeftMax);
        int rightMin = Math.min(nums1RightMin, nums2RightMin);
        if ((m + n) % 2 == 1) {
            return (double) leftMax;
        } else {
            return ((double) leftMax + (double) rightMin) / 2.0;
        }
    }
}
### 计算两个序数合并后的中位数 为了找到两个已排序数 `nums1` 和 `nums2` 合并后的中位数,可以采用二分查找的方法来满足 O(log(min(m, n))) 的时间复杂度要求。以下是详细的算法说明以及实现。 #### 算法思路 通过将问题转化为寻找第 k 小的元素,可以在不实际合并数的情况下高效地定位中位数的位置。具体方法如下: - 如果总长度 `(m + n)` 是奇数,则中位数是第 `(m + n) / 2 + 1` 小的元素;如果是偶数,则需要分别找到第 `(m + n) / 2` 和第 `(m + n) / 2 + 1` 小的元素,并取其平均值作为最终结果[^1]。 - 使用递归的方式,在每次迭代中丢弃掉不可能成为目标元素的部分数据,从而缩小搜索范围。 #### 实现代码 下面是一个基于 Python 的解决方案: ```python def findMedianSortedArrays(nums1, nums2): def get_kth_element(k): index1, index2 = 0, 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]) # 常情况下的逻辑 new_index1 = min(index1 + k // 2 - 1, m - 1) new_index2 = min(index2 + k // 2 - 1, n - 1) pivot1, pivot2 = nums1[new_index1], 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 m, n = len(nums1), len(nums2) total_length = m + n if total_length % 2 == 1: return get_kth_element((total_length + 1) // 2) else: left = get_kth_element(total_length // 2) right = get_kth_element(total_length // 2 + 1) return (left + right) / 2 # 测试用例 nums1 = [1, 3] nums2 = [2] result = findMedianSortedArrays(nums1, nums2) print(result) # 输出应为 2.0 ``` 上述代码定义了一个辅助函数 `get_kth_element` 来获取两数中的第 k 小元素。该函数利用了二分的思想逐步减少候选集合规模直到锁定目标位置。 #### 复杂度分析 此解法的时间复杂度主要由递归调用次数决定,由于每轮都会排除大约一半的数据量,因此整体性能达到预期的 O(log(min(m, n))) 时间复杂度。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值