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

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

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

相关推荐
6Hzlia17 小时前
【Hot 100 刷题计划】 LeetCode 189. 轮转数组 | C++ 三次反转经典魔法 (O(1) 空间)
c++·算法·leetcode
m0_6294947318 小时前
LeetCode 热题 100-----13.最大子数组和
数据结构·算法·leetcode
田梓燊18 小时前
力扣:94.二叉树的中序遍历
数据结构·算法·leetcode
khalil102018 小时前
代码随想录算法训练营Day-38动态规划06 | 322. 零钱兑换、279.完全平方数、139.单词拆分、多重背包、总结
数据结构·c++·算法·leetcode·动态规划
阿Y加油吧18 小时前
二刷 LeetCode:300. 最长递增子序列 & 152. 乘积最大子数组 复盘笔记
笔记·算法·leetcode
6Hzlia18 小时前
Hot 100 刷题计划】 LeetCode 146. LRU 缓存 | C++ 哈希表+双向链表
c++·leetcode·缓存
程序员小远18 小时前
如何编写测试用例?
自动化测试·软件测试·python·功能测试·测试工具·职场和发展·测试用例
Android_xiong_st18 小时前
(原创)2026安卓面试复盘
android·面试·职场和发展
我不是懒洋洋18 小时前
【数据结构】二叉树OJ(单值二叉树、检查两棵树是否相同、对称二叉树、二叉树的前序遍历、另一颗树的子树)
c语言·数据结构·c++·经验分享·算法·leetcode·visual studio
阿Y加油吧18 小时前
二刷 LeetCode:5. 最长回文子串 & 1143. 最长公共子序列 复盘笔记
笔记·算法·leetcode