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

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

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

相关推荐
hn小菜鸡1 小时前
LeetCode 2058.找出临界点之间的最小和最大距离
算法·leetcode·职场和发展
liuyang-neu1 小时前
力扣 简单 70.爬楼梯
java·算法·leetcode
IronmanJay1 小时前
【LeetCode每日一题】——862.和至少为 K 的最短子数组
数据结构·算法·leetcode·前缀和·双端队列·1024程序员节·和至少为 k 的最短子数组
OT.Ter1 小时前
【力扣打卡系列】二分查找(搜索旋转排序数组)
算法·leetcode·职场和发展·go·二分查找
Ddddddd_1581 小时前
C++ | Leetcode C++题解之第504题七进制数
c++·leetcode·题解
J_z_Yang1 小时前
LeetCode 202 - 快乐数
c++·算法·leetcode
Mopes__1 小时前
Python | Leetcode Python题解之第517题超级洗衣机
python·leetcode·题解
pengpeng021 小时前
力扣每日一题 685. 冗余连接 II
算法·leetcode
测试老哥3 小时前
Python+Selenium+Pytest+POM自动化测试框架封装(完整版)
自动化测试·软件测试·python·selenium·测试工具·职场和发展·测试用例
西几5 小时前
代码训练营 day48|LeetCode 300,LeetCode 674,LeetCode 718
c++·算法·leetcode