【递归打卡1】在两个长度相等的排序数组中找到上中位数
【题目】
给定两个有序数组arr1和arr2,已知两个数组的长度都为N,求两个数组中所有数的上中位数。要求时间复杂度O(logN),空间复杂度O(1)
【举例】
例如 arr1 = [1, 2,3,4],arr2 = [3,4,5,6]。
总共8个数,则中位数就是第 4 小的数,为 3.
例如 arr1 = [0,1,2],arr2 = [3,4,5]。
总共6个数,则中位数就是第 3 小的数,为 2.
【难度】
中
解答
这道题可以采用递归来解决,注意,这道题数组是有序的,所以它有如下特点:
(1)、当 两个数组的长度为偶数时:
我来举个例子说明他拥有的特点吧。我们假定
arr1 = [1, 2,3,4],arr2 = [3,4,5,6]。则数组的长度为 n = 4。
分别选出这两个数组的上中位数的下标,即
mid1 = (n-1)/2 = 1。
mid2 = (n - 1)/2 = 1。
假如 arr2[mid2] > arr2[mid1],那么我们要找的目标数是一定存在于 arr1[mid1+1...n] 和 arr2[0...mid2]中。而不可能存在于 arr1[0...mid1] 和 arr2[mid2+1...n] 之中。
也就是说,我们接下来只需要在arr1[mid1+1...n] 和 arr2[0...mid2] 中查找就行了。
(2)、当两个数组的长度为奇数时:
假定 arr1 = [1, 2,3,4,5],arr2 = [3,4,5,6,7]。则数组的长度为 n = 5。
mid1 = (n-1)/2 = 2。
mid2 = (n - 1)/2 = 2。
这个时候如果 arr2[mid2] > arr1[mid1] 时,则和上面那个情况有点小差别,这时候目标数只存在于 arr1[mid1...n] 和 arr2[0...mid2]中。注意他们的差别,从arr1[mid1+1...n] => arr1[mid1...n]。
理解了这个原理,配合上代码会更好理解,代码如下:
public static int getUpMedian(int[] arr1, int[] arr2) {
if(arr1 == null || arr2 == null )
return -1;
// 开始寻找
return find(arr1, 0, arr1.length - 1, arr2, 0, arr2.length - 1);
}
public static int find(int[] arr1, int l1, int r1, int[] arr2, int l2, int r2) {
int mid1 = l1 + (r1 - l1) / 2;
int mid2 = l2 + (r2 - l2) / 2;
// 表示数组只剩下一个数,把两个数组中较小的数返回去
if (l1 >= r1) {
return Math.min(arr1[l1], arr2[l2]);
}
// 元素个数为奇数,则offset为0,为偶数则 offset 为 1
int offset = ((r1 - l1 + 1) & 1) ^ 1;// 用位运算比较快
if (arr1[mid1] < arr2[mid2]) {
return find(arr1, mid1+offset, r1, arr2, l2, mid2);
} else if (arr1[mid1] > arr2[mid2]) {
return find(arr1, l1, mid1, arr2, mid2 + offset, r2);
} else {
return arr1[mid1];// 返回 arr2[mid2]也可以。
}
}
也可以用迭代来做,反而更加简单,迭代版本如下:
// 迭代版本
public int getUpMedian2(int[] arr1, int[] arr2) {
if (arr1 == null || arr2 == null) {
return -1;
}
int l1 = 0;
int r1 = arr1.length - 1;
int l2 = 0;
int r2 = arr2.length - 1;
int mid1 = 0;
int mid2 = 0;
int offset = 0;
while (l1 < r1) {
mid1 = l1 + (r1 - l1) / 2;
mid2 = l2 + (r2 - l2) / 2;
offset = ((r1 - l1 + 1) & 1)^1;
if (arr1[mid1] < arr2[mid2]) {
l1 = mid1 + offset;
r2 = mid2;
} else if (arr1[mid1] > arr2[mid2]) {
r1 = mid1;
l2 = mid2 + offset;
} else {
return arr2[mid1];
}
}
return Math.min(arr1[l1], arr2[l2]);
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?