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

要找到两个正序数组的中位数,并且满足时间复杂度为 O(log (m + n)),我们可以使用二分查找的方法。以下是详细的解题思路和 Java 代码实现。

解题思路

  1. 定义问题:中位数是将两个有序数组合并后,找到中间的值。如果总长度为奇数,中位数是中间的元素;如果总长度为偶数,中位数是中间两个元素的平均值。

  2. 使用二分查找

    • 确保我们总是在较小的数组上进行二分查找,这样可以保证算法的高效性。
    • 设定两个指针分别指向数组的开头和结尾,进行二分查找,找到一个合适的划分点 ij 使得:
      • i + j = (m + n + 1) / 2(保证左边部分包含中位数)
      • 左边最大值小于等于右边最小值:
        • nums1[i - 1] <= nums2[j]
        • nums2[j - 1] <= nums1[i]
  3. 划分逻辑

    • 如果 nums1[i - 1] > nums2[j],说明 i 太大,需要减小 i
    • 如果 nums2[j - 1] > nums1[i],说明 i 太小,需要增大 i
  4. 计算中位数

    • 如果总长度为奇数,中位数为左边部分的最大值。
    • 如果总长度为偶数,中位数为左边最大值和右边最小值的平均值。

Java 代码实现

java 复制代码
public class MedianOfTwoSortedArrays {

    /**
     * 寻找两个正序数组的中位数
     *
     * @param nums1 数组1
     * @param nums2 数组2
     * @return 中位数
     */
    public static double findMedianSortedArrays(int[] nums1, int[] nums2) {
        int m = nums1.length;
        int n = nums2.length;

        // 确保 nums1 是较短的数组
        if (m > n) {
            return findMedianSortedArrays(nums2, nums1);
        }

        int imin = 0, imax = m, halfLen = (m + n + 1) / 2;
        while (imin <= imax) {
            int i = (imin + imax) / 2; // nums1 的划分点
            int j = halfLen - i; // nums2 的划分点

            // 调整二分查找范围
            if (i < imax && nums2[j - 1] > nums1[i]) {
                imin = i + 1;  // i 太小,增加 i
            } else if (i > imin && nums1[i - 1] > nums2[j]) {
                imax = i - 1;  // i 太大,减少 i
            } else {  // i 正确
                int maxOfLeft;
                if (i == 0) {
                    maxOfLeft = nums2[j - 1];  // nums1 空
                } else if (j == 0) {
                    maxOfLeft = nums1[i - 1];  // nums2 空
                } else {
                    maxOfLeft = Math.max(nums1[i - 1], nums2[j - 1]);  // 左边部分的最大值
                }

                if ((m + n) % 2 == 1) {
                    return maxOfLeft;  // 奇数长度
                }

                int minOfRight;
                if (i == m) {
                    minOfRight = nums2[j];  // nums1 空
                } else if (j == n) {
                    minOfRight = nums1[i];  // nums2 空
                } else {
                    minOfRight = Math.min(nums1[i], nums2[j]);  // 右边部分的最小值
                }

                // 偶数长度,返回两个中位数的平均值
                return (maxOfLeft + minOfRight) / 2.0;
            }
        }

        return 0.0; // 这行理论上不会执行
    }

    public static void main(String[] args) {
        int[] nums1 = {1, 3}; // 示例数组1
        int[] nums2 = {2};    // 示例数组2
        double result = findMedianSortedArrays(nums1, nums2); // 调用函数
        System.out.println(result); // 输出中位数
    }
}

代码说明

  1. 函数 findMedianSortedArrays

    • 通过二分查找确定合适的划分点 ij
    • 计算并返回中位数。
  2. 主方法 main

    • 提供示例数组并调用中位数计算函数,输出结果。

示例

对于输入:

  • nums1 = [1, 3]
  • nums2 = [2]

合并后的数组为 [1, 2, 3],中位数为 2

对于输入:

  • nums1 = [1, 2]
  • nums2 = [3, 4]

合并后的数组为 [1, 2, 3, 4],中位数为 (2 + 3) / 2 = 2.5

该算法有效且符合时间复杂度要求。

相关推荐
橘颂TA38 分钟前
【剑斩OFFER】算法的暴力美学——两数之和
数据结构·算法·leetcode·力扣·结构与算法
云里雾里!1 小时前
力扣 268. 缺失数字 ✅ 【位运算(异或)最优解法】深度解析
算法·leetcode
梭七y1 小时前
【力扣hot100题】(122)回文链表
算法·leetcode·链表
web小白成长日记1 小时前
自定义 Hooks 的用法和意义详解(结合案例)
前端·css·面试·职场和发展·前端框架
alphaTao2 小时前
LeetCode 每日一题 2025/12/29-2026/1/4
算法·leetcode
ShaderJoy2 小时前
ShaderJoy —— 《对称镜面下的绞肉机》【算法悬疑短文】【Python】
算法·leetcode·面试
有一个好名字2 小时前
力扣-盛最多水的容器
算法·leetcode·职场和发展
技术狂人1683 小时前
(六)大模型算法与优化 15 题!量化 / 剪枝 / 幻觉缓解,面试说清性能提升逻辑(深度篇)
人工智能·深度学习·算法·面试·职场和发展
技术狂人1683 小时前
(七)大模型工程落地与部署 10 题!vLLM/QPS 优化 / 高可用,面试实战必备(工程篇)
人工智能·深度学习·面试·职场和发展·vllm
im_AMBER3 小时前
Leetcode 95 分割链表
数据结构·c++·笔记·学习·算法·leetcode·链表