LeetCode 4. 寻找两个正序数组的中位数
思路:我们只关注从nums1中取多了、取少了、或者刚刚好。 假设 nums1 中有 n 个元素,我们二分的取[1,n]
个元素,取0个元素作为边界情况特殊处理
变量名约定:
变量名 | 描述 |
---|---|
leftPartSize | 左部分个数: 中位数及其左边元素个数 |
totalSize | 元素总个数 |
num1 | 从nums1中取 num1个元素 |
num2 | 从nums2中取 num2 个元素 |
- leftPartSize = totalSize / 2 +1(奇偶数都正确)
- num1+num2 = leftPartSize (奇偶数都正确)
- totalSize,leftPartSize是固定的
已知 totalSize(nums1.len+nums2.len),可以求出 leftPartSize。剩下的就是确定 num1和num2。我们在区间[1,nums1.length] 二分的查找num1,通过 num2 = leftPartSize -num1 计算出 num2,然后判断 num1取的是否合适,取多了,还是少了
变量名讲解
-
单数组为例
-
双数组边界情况 左部分全在一个数组中
-
双数组一般情况
边界情况分析 以只取 num1 为例
中位数及其左边的元素个数为 leftPartSize
,如果只取num1则应该满足:
-
nums2为空数组
-
nums1的长度大于 leftPartSize,并且 nums1的第leftPartSize个元素的是小于等于nums2第一个元素
其代码如下:
public boolean borderCase(int[] ary,int[] otherAry,int leftPartSize){
// 只在num1中取
if(otherAry.length==0||ary.length>=leftPartSize && ary[leftPartSize-1]<=otherAry[0]){
return true;
}
return false;
}
明确二分流程
我们在区间[1,nums1.len]
二分查找合适的 num1
使其满足 nums1[num1-1]
和nums2[num2-1]
是候选中位数。
left = 1;
right = nums1.length+1;
while(left<right){
num1 = (left+right)/2;
if(num1刚好合适){
return 中位数
}
else if(num1取少了){
left = num1+1;
}
else{
right = num1;
}
}
num1取得刚好合适
如果num1选取正合适,那么 nums1[num1-1]
与nums2[num2-1]
都是左部分,一定小于右部分的最小的元素
Math.max(nums1[num1-1], nums2[num2-1])<=Math.min(nums1[num1],nums2[num2]);
考虑 num2 边界情况
Math.max(nums1[num1-1], nums2[num2-1])<=Math.min(num1!=nums1.length?nums1[num1]:Integer.MAX_VALUE,num2!=nums2.length?nums2[num2]:Integer.MAX_VALUE)
nums1取多了
nums1取多了,导致 num1 增大,nums[num1-1]也增加,我们只需判断 nums1[num1-1]>nums2[num2-1]
就好了
程序流程
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
int totalSize = nums1.length+nums2.length;
int leftPartSize = totalSize/2+1;
boolean edgeFlag;
boolean isEven;
// 边界情况 左部分只在nums1中
if(borderCase(nums1,nums2,leftPartSize)){
// 获取边界情况的解
return getBorderSolution(nums1,leftPartSize,totalSize);
}
// 边界情况 左部分只在nums2中
if(borderCase(nums2,nums1,leftPartSize)){
// 获取边界情况的解
return getBorderSolution(nums2,leftPartSize,totalSize);
}
// 进入正常情况
return normalCase(nums1,nums2,leftPartSize,totalSize);
}
public double normalCase(int[] nums1, int[] nums2, int leftPartSize,int totalSize){
left = 1;
right = nums1.length+1;
while(left<right){
num1 = (left+right)/2;
num2 = leftPartSize - num1;
// num2是否越界检测 ...
if(num1刚好合适){
return 中位数
}
else if(num1取少了){
left = num1+1;
}
else{
right = num1;
}
}
}