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

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

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

相关推荐
SylviaW081 小时前
python-leetcode 37.翻转二叉树
算法·leetcode·职场和发展
玦尘、1 小时前
位运算实用技巧与LeetCode实战
算法·leetcode·位操作
白初&2 小时前
安全面试4
安全·面试·职场和发展
夏末秋也凉2 小时前
力扣-回溯-93 复原IP地址
算法·leetcode
BingLin-Liu4 小时前
蓝桥杯备考:递归初阶
职场和发展·蓝桥杯
01_5 小时前
力扣hot100 ——和为k的子数组 前后缀和(积)各种情况总结
数据结构·算法·leetcode·前后缀和(积)计算
_Itachi__6 小时前
LeetCode 热题 100 206. 反转链表
算法·leetcode·链表
南宫生6 小时前
力扣每日一题【算法学习day.130】
java·学习·算法·leetcode
柠石榴6 小时前
【练习】【类似于子集问题】力扣491. 非递减子序列/递增子序列
c++·算法·leetcode·回溯
干饭高手6 小时前
Day9,Hot100(图论)
python·leetcode·图论