题目描述
解法
这道题目假如采取最普通的做法,即为将两个数组结合在一起,再进行排序,然后取出直接取出中位数即可。排序的算法最优复杂度为 O(nlogn),而取出中位数的复杂度为O(n),遍历两个数组的复杂度也是O(n),所以整个算法的复杂度为O(nlogn),明显超过题目的要求,不可采取
不过最后在accepted列表里发现有人采取这种方法然后LeetCode给过的。
这里附上这种方法的代码
class Solution {
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
int[] nums = new int[nums1.length + nums2.length];
int p1 =0;
int p2 =0;
int i;
for(i =0;p1<nums1.length && p2<nums2.length && i<nums.length;i++){
if(nums1[p1]> nums2[p2]){
nums[i] = nums2[p2];
p2++;
}else{
nums[i] = nums1[p1];
p1++;
}
}
while(p1< nums1.length){
nums[i] = nums1[p1];
p1++;
i++;
}
while(p2< nums2.length){
nums[i] = nums2[p2];
p2++;
i++;
}
if(nums.length%2==1){
return nums[nums.length/2];
}
return (nums[nums.length/2] + nums[nums.length/2-1] )/2.0;
}
}
接着思考第二种方法。要达到log,必须采取二分。一开始的思路是取num1数组的中位数a,接着取num2数组的中位数b,那么中位数必然在a 和 b中间。但只能确定这一步的范围。
举例说明,假如a < b, 那么中位数在a, b之间,假如你把小于a的部分砍掉,把大于b的部分砍掉,那么此时数的奇偶性就会改变,你最后求得的中位数必然会有偏差。
因此不可以采用丢弃的方法来解决这道题
最后采取了答案的方法
假如将两个数组分成left part和right part
然后满足
那么中位数就可以通过
需要满足的条件即为
那么如何找到这个i呢,即通过二分法搜索就能够达到O(logn)的复杂度
搜索过程中一共有一下三种情况
根据大小,决定二分法取中值的方向
找到i之后,就能够确定中值
代码如下
class Solution {
public double findMedianSortedArrays(int[] A, int[] B) {
int m = A.length;
int n = B.length;
if (m > n) { // to ensure m<=n
int[] temp = A; A = B; B = temp;
int tmp = m; m = n; n = tmp;
}
int iMin = 0, iMax = m, halfLen = (m + n + 1) / 2;
while (iMin <= iMax) {
int i = (iMin + iMax) / 2;
int j = halfLen - i;
if (i < iMax && B[j-1] > A[i]){
iMin = i + 1; // i is too small
}
else if (i > iMin && A[i-1] > B[j]) {
iMax = i - 1; // i is too big
}
else { // i is perfect
int maxLeft = 0;
if (i == 0) { maxLeft = B[j-1]; }
else if (j == 0) { maxLeft = A[i-1]; }
else { maxLeft = Math.max(A[i-1], B[j-1]); }
if ( (m + n) % 2 == 1 ) { return maxLeft; }
int minRight = 0;
if (i == m) { minRight = B[j]; }
else if (j == n) { minRight = A[i]; }
else { minRight = Math.min(B[j], A[i]); }
return (maxLeft + minRight) / 2.0;
}
}
return 0.0;
}
}
最后复杂度为O(log(min{m, n}))。只需要选择数量较小的一个数组进行搜索即可