![]()
public double findMediandArrays(int[] A ,int[] B){
int m = A.length;
int n = B.length;
// 长度无所谓 但是必须知道 谁长谁短 这里涉及取值范围的问题
if(m>n){
// 尾递归不会栈堆积
findMediandArrays(B,A);
}
// I的取值范围 最小为 0 最大值为 m
int maxI = m,minI = 0;
while (maxI>=minI){
// 这个i不是坐标 是数组A切割点的位置与实际坐标有差异 一定要明确这点这也是困扰我很久的问题
// 这里是将 数组A 一分为二 取到了A的中位数
// 如果A为奇数 中位数为i 为偶数 中位数为 2分之 A[i]+A[i-1]
// [1,2,3] [1,2,3,4] 有兴趣自己代入一下
int i = (maxI+minI)/2;
// 这里是 数组B的切割点 这个切割点和 i 相关也就是 通过i 求 j
// 因为中位数的位置不变 永远是(m+n)/2 所以求出了一个得知一个数组的切割位置就知道另一个的切割点
// 这也是之前为什么要区分长短的原因 如果不区分长短 j 有可能为负数
// 为什么加一呢是 奇偶合并 这里的合并不是 偶数合并为奇数
// 而是奇数合并为偶数 也就是说总长度为偶数
// 中位数永远左节点为 (m+n)/2 -1 右节点分为 (m+n)/2
// 如果为奇数返回 做节点 如果为偶数返回左右节点的均值
int j = (m+n+1)/2-i;
// 移动切割点 这里要先确认结果 再想条件
// 结果是 i 增加还是减小
if (i!=m&&j!=0 && A[i]<B[j-1]){
// i增加 j就会减小 j的最小值为0 i的最大值为 m
// 所以 i增加要满足 i!=m j!=0
// 然后理解什么是中位数
// 因为数组有序 所以 A[i]> A[i-1]
// 因为数组有序 所以 B[j]> B[j-1]
// 如果 A[i]<B[j-1] 则需要增加i 减小 j 使其接近中位数条件
// 左边最大值 小于右面最小值
// 所以 i要增大
minI = minI + 1;
}
//这里是结果是i减小同理
else if (i!=0&&j!=n&&A[i-1]>B[j] ){
maxI = maxI - 1;
}// 当切割点不再变更 则 找到中位数切割位置 开始求值
else {
// 左边最大值
int leftMax = 0;
if (i == 0 ){
// 左边最大值 i 和j 是切割点不是坐标
leftMax = B[j-1];
}else if(j==0){
leftMax = A[i-1];
}else {
leftMax = Math.max( B[j-1], A[i-1]);
}
//这个地方 不要用一个数组代入 想想中位数 因为 这个题解一切以中位数为基础的理论
// 代入时要用两个有序数组 一个数组 无法代入
// 如果是奇数 直接返回左边最大值就可以
if (((m+n)&1)==1){
return leftMax;
}
//右边最小值 求职同理
int rightMin = 0;
if (i == m ){
// 左边最大值 i 和j 是切割点不是坐标
rightMin = B[j];
}else if(j==n){
rightMin = A[i];
}else {
rightMin = Math.min(B[j], A[i]);
}
return (leftMax+rightMin)/2.0;
}
}
return 0.0;
}