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

要找到两个正序数组的中位数,并且满足时间复杂度为 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

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

相关推荐
圣保罗的大教堂1 小时前
leetcode 3742. 网格中得分最大的路径 中等
leetcode
hqyjzsb3 小时前
规划工商管理大学成长:搭建四层能力体系,重视高阶的 AI 能力建设
开发语言·人工智能·python·microsoft·职场和发展·数据挖掘·业界资讯
我不会起名字3223 小时前
一天一道算法题(35):电话号码的字母组合
java·数据结构·后端·python·leetcode·go·回溯
圣保罗的大教堂4 小时前
leetcode 2033. 获取单值网格的最小操作数 中等
leetcode
6Hzlia4 小时前
【Classic 150 刷题计划】 LeetCode 242. 有效的字母异位词 | C++ 哈希计数与严密防线
c++·算法·leetcode
wabs6664 小时前
关于二叉树【力扣101.对称二叉树的思考】
数据结构·c++·算法·leetcode·二叉树
6Hzlia4 小时前
【Classic 150 刷题计划】 LeetCode 228. 汇总区间 | C++ 双游标区间扫描与 to_string 规范
c++·算法·leetcode
小刘在重生~5 小时前
十六(3)、《集合扩充》CopyOnWriteArrayList 超详细解析(线程安全集合)
java·笔记·面试·职场和发展
玖玥拾5 小时前
LeetCode 383 赎金信
算法·leetcode
橘子汽水1686 小时前
Leetcode 763,45 划分字母区间 跳跃游戏II
数据结构·算法·leetcode