1、问题描述
这道题的边界判断比较的多,如果是边测试边界边编写判断语句的话,一点点的总能成功(我就是这样),如果要一口气分析的话属实有点麻烦。
下面是具体思路:
1、我们总能用一刀将两个数组各切成两半。
切完之后呢,在nums1中,切线左边所有元素肯定小于右边所有元素,即L_MAX1 <= R_MIN1 。同样,在nums2中,L_MAX2 <= R_MIN2 。
2、这一刀我们应该切在哪里呢?
重点:如果我们能切下一刀,满足
L_MAX1 <= R_MIN2 && L_MAX2 <= R_MIN_1
那么,假设 numsSize1 + numsSize2 = 奇数,中位数就是切线左边最大的数; numsSize1 + numsSize2 = 偶数,中位数就是切线左边最大的数与切线右边最小的数的平均数。
如上图所示,切线左边最大的是nums1的3,切线右边最小的是nums2的4,则中位数就是3.5。
其实我们可以将其归结为寻找两个有序数组的第k小的元素。
nums1[ i ] , nums2[ j ]
满足: i + j = k。
那么寻找中位数呢
int size_left = (nums1Size + nums2Size + 1)/2
满足 i + j = size_left 即可。
2、通过代码解释更清楚
(以下代码都是按顺序解释,没有删减)
2.1、定义与初始化
double findMedianSortedArrays(int* nums1, int nums1Size, int* nums2, int nums2Size){
int size_left = (nums1Size + nums2Size + 1)/2; //表示两个数组合并后中位数左边的个数。
int i = 0, j = size_left-i; // i + j = size_left
// i负责从头遍历nums1 , j 负责从尾端后往前遍历nums2
double max_left,min_right; // max_left 用来存储切线左边最大值,min_right 用来存储切线右边最小值
我们将长度较小的数组放在nums1 中,方便之后的操作。
if(nums1Size > nums2Size){
int *temp,t;
temp = nums1;
nums1 = nums2;
nums2 = temp;
t = nums1Size;
nums1Size = nums2Size;
nums2Size = t;
}
2.2、中间部分
我将if else 语句分开解释,便于理顺思路。
if(nums1Size==0 && nums2Size==0) // 若两个数组都为空,则直接返回0
return 0;
else if(nums1Size==0){ // 如果第一个数组为空,那我们直接从第二个数组找到中位数就可以了。
max_left = nums2[(nums2Size-1)/2];
min_right = nums2[nums2Size/2];
}
else{
while(i<=nums1Size){ // 当i有效的时候
if(i == nums1Size){ // 详见情况【1】
if(j==0)
max_left = nums1[i-1];
else
max_left = nums1[i-1]>nums2[j-1]?nums1[i-1]:nums2[j-1];
min_right = nums2[j];
break;
}
else if(nums1[i]>=nums2[j-1]){
if(i==0){ // 详见情况【2】
if(j==nums2Size)
min_right = nums1[i];
else
min_right = nums1[i]<nums2[j]?nums1[i]:nums2[j];
max_left = nums2[j-1];
break;
}
// 若不是边界值则 正常判断。
max_left = nums1[i-1]>nums2[j-1]?nums1[i-1]:nums2[j-1];
min_right = nums1[i]<nums2[j]?nums1[i]:nums2[j];
break;
}
else{
i++; // 继续往下一个元素遍历
j = size_left-i; // 受i的约束,保持关系
}
}
}
边界值情况
// 最后判断奇偶数,输出中位数
if((nums1Size + nums2Size)%2 == 0)
return (max_left+min_right)/2;
else
return max_left;
}
3、完整代码
double findMedianSortedArrays(int* nums1, int nums1Size, int* nums2, int nums2Size){
int size_left = (nums1Size + nums2Size + 1)/2; //表示两个数组合并后中位数左边的个数。
int i = 0, j = size_left-i;
double max_left,min_right;
if(nums1Size > nums2Size){
int *temp,t;
temp = nums1;
nums1 = nums2;
nums2 = temp;
t = nums1Size;
nums1Size = nums2Size;
nums2Size = t;
}
if(nums1Size==0 && nums2Size==0)
return 0;
else if(nums1Size==0){
max_left = nums2[(nums2Size-1)/2];
min_right = nums2[nums2Size/2];
}
else{
while(i<=nums1Size){
if(i == nums1Size){
if(j==0)
max_left = nums1[i-1];
else
max_left = nums1[i-1]>nums2[j-1]?nums1[i-1]:nums2[j-1];
min_right = nums2[j];
break;
}
else if(nums1[i]>=nums2[j-1]){
if(i==0){
if(j==nums2Size)
min_right = nums1[i];
else
min_right = nums1[i]<nums2[j]?nums1[i]:nums2[j];
max_left = nums2[j-1];
break;
}
max_left = nums1[i-1]>nums2[j-1]?nums1[i-1]:nums2[j-1];
min_right = nums1[i]<nums2[j]?nums1[i]:nums2[j];
break;
}
else{
i++;
j = size_left-i;
}
}
}
if((nums1Size + nums2Size)%2 == 0)
return (max_left+min_right)/2;
else
return max_left;
}