LeetCode热题100 刷题笔记(第四天)二分 「 寻找两个正序数组的中位数」

前言

这几天不是在写文章总结黑马点评吗,感觉敲代码的能力确实有点欠缺了,主要是敲项目代码的时候,接入了AI,大部分代码都是直接按Tab键自动生成的,代码能力确实有一点退步了🤪🤪🤪,这几天学学数据结构,刷刷题🏄🏄🏄,冲冲冲一天一道,(但是我感觉可能坚持不下去🤪)

题目

给定两个大小分别为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的 中位数

算法的时间复杂度应该为 O(log (m+n)) 。

示例 1:

输入:nums1 = [1,3], nums2 = [2]

输出:2.00000

解释:合并数组 = [1,2,3] ,中位数 2

示例 2:

输入:nums1 = [1,2], nums2 = [3,4]

输出:2.50000

解释:合并数组 = [1,2,3,4] ,中位数 (2 + 3) / 2 = 2.5

提示:

nums1.length == m

nums2.length == n

0 <= m <= 1000

0 <= n <= 1000

🧩 解题思路

这道题的本质是:在两个有序数组中,找到合并后第 k 小的元素 ,中位数就是特殊的第 k 小元素(总长度为奇数时取中间,偶数时取中间两个的平均)。

java 复制代码
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
  int m = nums1.length;
  int n = nums2.length;
  int total = m + m;
  //总长度为奇数: 找第 (total + 1)/2 小
  //总长度为偶数: 找第 total/2 小 和 第(total/2)+1 小,再取平均
  if(total % 2 == 1) {
     return getk(nums1, nums2, 0, m-1, 0, n-1, (total+1)/2);
  } else {
     int k1 = total / 2;
     int k2 = k1 + 1;
     return (getk(nums1, nums2, 0, m-1, 0, n-1, k1) + getk(nums1, nums2, 0, m-1, 0, n-1, k2)) / 2.0;  
  }
}


// 参数含义:
// nums1, nums2:两个有序数组
// l1, r1:nums1 当前考虑的区间[l1, r1]
// l2, r2:nums2 当前考虑的区间[l2, r2]


int getk(int[] nums1, int[] nums2, int l1, int r1, int l2, int r2, int k) {
  int len1 = r1 - l1 + 1; //num1 当前区间长度
  int len2 = r2 - r2 + 1; //nums2 当前区间长度
 
  //1. 让nums1 始终是更短的数组, 减少二分次数
  if(len1 > len2) {
    return getk(nums2, nums1, l2, r2, l1, r1, k);
  }
  //2. 边界情况: 如果一个数组已经空了, 直接返回另一个数组的第k小
  if(len1 == 0){
    return nums2[l2 + k - 1];
  }
  //3. 边界情况: k=1, 返回两个数组当前元素的较小值
  if (k == 1) {
    return Math.min(nums1[l1], nums2[l2]);
  }
  //4. 二分: 分别在两个数组中提取「前 k/2 个元素」的位置
  //避免数组越界, 取 min(len1, k/2)
  int idx1 = l1 + Math.min(len1, k/2) - 1;
  int idx2 = l2 + Math.min(len2, k/2) - 1;
  //5.比较两个数组中第k/2小的元素, 排除较小的一半
  if (nums1[] > nums2[]){
    //nums2 的前k/2 个元素一定都比第k小元素小, 排除他们
    //新的k =  k-被排除的元素个数(idx2 - l2 +1)
    return getk(nums1, nums2, l1, r1,idx2 + 1, r2, k - (idx2 - l2 +1));
  } else {
    // nums1 的前 k/2 个元素一定都比第k小元素 小, 排除他们
    return getk(nums1, nums2, ids1 + 1, r1, l2, r2, k - (idx1 - l1 + 1));
  }
 
}

💡 核心逻辑拆解
1. 保证短数组优先 :if (len1 > len2) 交换两个数组,让 nums1 始终更短,减少后续二分的计算量。
2. 空数组处理 :如果一个数组区间为空,直接从另一个数组取第 k 小元素。
3. k=1 处理 :直接取两个数组当前区间首元素的较小值,就是第 1 小。
4. 二分排除

  • 每次在两个数组中取 k/2 长度的片段,比较片段末尾的元素。
  • 较小的那个片段里的所有元素,一定都比第 k 小元素小,可以直接排除。
  • 更新 k 和对应数组的区间起点,递归继续找。

✅ 示例运行

假设 nums1 = [1,3],nums2 = [2],总长度 = 3,中位数是第 2 小:

  1. 调用 getK(..., k=2)
  • len1=2, len2=1 → 不交换
  • k≠1,取 k/2=1
  • idx1=0, idx2=0
  • nums1[0]=1 < nums2[0]=2 → 排除 nums1 前 1 个元素
  • 新调用:getK(nums1, nums2, 1, 1, 0, 0, 2-1=1)
  1. 新调用 k=1 → 返回 min(nums1[1]=3, nums2[0]=2) = 2
  2. 中位数就是 2,正确。
    ⚠️ 关键技巧
  • 二分思想:每次排除 k/2 个元素,将问题规模减半,时间复杂度 O (log k) → 最终 O (log (min (m,n)))。
  • 避免越界:用 Math.min(len, k/2) 保证取的位置不超过数组当前区间长度。
  • 递归边界:空数组和 k=1 是递归的终止条件,保证不会无限递归。

如果还不理解题目建议可以去学学二分法, 可以看看我这篇文章 数据结构09(Java)-- 二分查找模板

小白啊!!!写的不好轻喷啊🤯如果觉得写的不好,点个赞吧🤪(批评是我写作的动力)

...。。。。。。。。。。。...

...。。。。。。。。。。。...

相关推荐
_日拱一卒2 小时前
LeetCode:最小覆盖字串
java·数据结构·算法·leetcode·职场和发展
小O的算法实验室2 小时前
2026年IEEE TEVC,面向农业多机器人任务分配的自适应多目标任务划分算法,深度解析+性能实测
算法·机器人·论文复现·智能算法·智能算法改进
Ujimatsu2 小时前
数据分析相关面试题-A/B 测试 & 统计学部分
算法·机器学习·数据分析
郝学胜-神的一滴2 小时前
Qt6 + OpenGL 3.3 渲染环境搭建全指南:从空白窗口到专属渲染画布的优雅实现
数据结构·c++·线性代数·算法·系统架构·图形渲染
Omics Pro2 小时前
空间组学下一代机器学习与深度学习
大数据·人工智能·深度学习·算法·机器学习·语言模型·自然语言处理
llm大模型算法工程师weng2 小时前
在flomo中安放“不确定”:一款笔记产品如何让人“被看见”
笔记
小肥米2 小时前
分块查找ASL公式推导,为什么是两个ASL之和
数据结构·算法
样例过了就是过了2 小时前
LeetCode热题100 最小栈
数据结构·c++·算法·leetcode
计算机安禾2 小时前
【数据结构与算法】第18篇:数组的压缩存储:对称矩阵、三角矩阵与稀疏矩阵
c语言·开发语言·数据结构·c++·线性代数·算法·矩阵