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

题目

题目链接

解题思路

  • 不能合并两个数组,合并两个数组需要每个数组进行遍历,时间复杂度是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;
}
相关推荐
有点。1 小时前
C++03阶段练习(一)
数据结构·c++
小羊没烦恼!1 小时前
Memory 记忆设计讨论:Agent Memory 的安全边界:权限、删除、版本与回执
java·大数据·word·powerpoint·.net
这是程序猿1 小时前
Java线程池深度剖析:源码原理、核心参数、任务调度与生产调优实战
java·开发语言·python
rannn_1111 小时前
【Java面试八股】Java基础篇|数据类型、面向对象、关键字、反射、注解、异常、新特性、序列化、设计模式、IO
java·后端·面试
MacroZheng1 小时前
阿里又开源了一个神级 Skill 项目!
java·人工智能·后端
kevin_kang2 小时前
第05章 实时语音识别的 ASR 原理
算法
kevin_kang2 小时前
第04章 断句原理:本地 VAD 与神经网络 VAD
算法
kevin_kang2 小时前
第06章 文字转语音的 TTS 原理
算法
6Hzlia2 小时前
【Classic 150 刷题计划】 LeetCode 123. 买卖股票的最佳时机 III | C++ 状态机动态规划与通用交易拓展
c++·算法·leetcode