【二分查找】【困难】寻找两个有序数组的中位数

题目

题目链接

解题思路

  • 不能合并两个数组,合并两个数组需要每个数组进行遍历,时间复杂度是O(m+n)

中位数:将整体排序数组分为左右两个相等的序列。

例如奇数数组为1,2,3,4,5 ,此时中位数为3

例如偶数数组为1,2,3,4,5,6 ,此时中位数为(3+4)/2=3.5

  • 分别切两个数组:保证切分后的数组结果左边最大的数 <= 右边最小的数
bash 复制代码
nums1 = [1,3,5,7]    ->    [1,3 | 5,7]
nums2 = [2,4,6,8]    ->    [2,4 | 6,8]

左半部分:[1,3] + [2,4]
右半部分:[5,7] + [6,8]
  • 整个数组一共有m + n 个元素。
    • 左半部分元素数量固定为 (m + n + 1) / 2 【奇数长度时左边比右遍多一个,这样的到的中位数就是左边的最大值】
    • 右半部分元素数量固定为 (m + n) / 2

两个数组的设定如下 ,切分时需要满足:max(left1, left2<=min(right1, right2)

nums1 左边最大值 = left1

nums1 右边最小值 = right1

nums2 左边最大值 = left2

nums2 右边最小值 = right2

代码

  • 注意:一定要让nums1是短数组
  • 这样二分次数更少,复杂度O(log(min(m,n)))
  • 防止 j 越界,当 nums1 比 nums2 长时,例如 nums1=2,nums2=\[\],此时计算 i=0,j=1,j!=0于是会计算nums2j - 1导致数组越界
java 复制代码
public static double findMedianSortedArrays(int[] nums1, int[] nums2) {
	//在较短的数组上二分
    if (nums1.length > nums2.length) {
        return findMedianSortedArrays(nums2, nums1);
    }
    int m = nums1.length;
    int n = nums2.length;
    int left_len = (m + n + 1) / 2;
    int right_len = (m + n) / 2;
    //初始化left和right
    int i = m/2;
    int j = left_len-i;
    //进行分割
    while(true){
        int left1 = i==0?Integer.MIN_VALUE: nums1[i-1];
        int left2 = j==0?Integer.MIN_VALUE: nums2[j-1];
        int right1 = i==m?Integer.MAX_VALUE: nums1[i];
        int right2 = j==n?Integer.MAX_VALUE: nums2[j];
        //nums1左侧太大
        if(left1>right2){
            i--;
            j++;
        }
        else if(left2>right1){
            i++;
            j--;
        }
        else{//分割正确
            //判断是否为偶数
            if((m+n)%2==0){
                return (Math.max(left1,left2)+Math.min(right1,right2))/2.0;
            }
            else{
                return Math.max(left1,left2);
            }
        }
    }
}
  • 修改成标准的二分:left,right分别表示数组1中的左右点值
  • left1 > right2 时,i 向左移动 right = i-1
  • left2 > right1 时,i 向右移动 left = i+1
java 复制代码
public static double findMedianSortedArrays(int[] nums1, int[] nums2) {
    // 保证 nums1 是较短数组
    if (nums1.length > nums2.length) {
        return findMedianSortedArrays(nums2, nums1);
    }
    int m = nums1.length;
    int n = nums2.length;
    int leftLen = (m + n + 1) / 2;
    int left = 0;
    int right = m;
    while (left <= right) {
        int i = left + (right - left) / 2;
        int j = leftLen - i;
        int left1 = i == 0 ? Integer.MIN_VALUE : nums1[i - 1];
        int left2 = j == 0 ? Integer.MIN_VALUE : nums2[j - 1];
        int right1 = i == m ? Integer.MAX_VALUE : nums1[i];
        int right2 = j == n ? Integer.MAX_VALUE : nums2[j];
        // nums1 左边太大,i 要减小
        if (left1 > right2) {
            right = i - 1;
        }
        // nums1 左边太少,i 要增大
        else if (left2 > right1) {
            left = i + 1;
        }
        // 分割正确
        else {
            if ((m + n) % 2 == 0) {
                return (Math.max(left1, left2) + Math.min(right1, right2)) / 2.0;
            } else {
                return Math.max(left1, left2);
            }
        }
    }
    return 0.0;
}
相关推荐
拓恒技术42 分钟前
无人机巡检AI算法的工程化落地:从需求到交付的5个核心环节
人工智能·算法·无人机
晨曦中的暮雨1 小时前
限流算法——固定窗口、滑动窗口、漏桶、令牌桶
java·开发语言·算法
怕浪猫1 小时前
Claude Code vs Codex:Computer Use 实现原理深度拆解
算法·面试·github
文丑颜不良啊2 小时前
LeetCode876~900题目解析
java·leetcode
罗西的思考3 小时前
AI 时代的 “房谋杜断”:如何培养能力、品味与判断力
人工智能·算法·机器学习
aloha_7893 小时前
Java 基础、集合、异常与 JUnit 5 速查
java·junit·sqlserver
淡海水3 小时前
07-02-源码-.NET Core GC分配路径
算法·unity·c#·.netcore·gc·1024程序员节
知守观4 小时前
设计模式实战:从真实老项目中看标准模板方法与工厂的落地
java·spring·设计模式
独隅4 小时前
Claude API 实战教程:从入门到完整项目
android·java·数据库·claude·claude code
Wang's Blog4 小时前
Java 项目实战: 交友项目 - 圈子功能实现:总结
java·开发语言·交友