There are two sorted arrays nums1 and nums2 of size m and n respectively.
Find the median of the two sorted arrays. The overall run time complexity should be O(log (m+n)).
Example 1:
nums1 = [1, 3] nums2 = [2] The median is 2.0
Example 2:
nums1 = [1, 2] nums2 = [3, 4] The median is (2 + 3)/2 = 2.5
public static double findMedianSortedArrays(int[] nums1, int[] nums2) {
int len1 = nums1.length;
int len2 = nums2.length;
int sum = len1 + len2;
int median = sum >> 1;
int[] numsTemp = null;
int[] numsTempOr = null;
int len = 0;
boolean lastgt = false;
boolean lastlt = false;
if (sum % 2 == 0) { // 偶数的时候
int index2 = len2 >> 1;
int index = 0;
numsTemp = nums2;
numsTempOr = nums1;
len = len1;
int medianSub1 = median - 1;
for (;;) {
if(numsTemp.length > 0 && index2 < numsTemp.length && index2 > -1)
index = binarySearch(numsTempOr, numsTemp[index2], len, median - index2);
else {
numsTemp = nums1;
numsTempOr = nums2;
index2 = len1 >> 1;
len = len2;
continue;
}
if (index + index2 == median) {
int index0 = index - 1;
if(index2 == 0)
return (numsTemp[index2] + numsTempOr[index0]) / 2.0;
index = binarySearch(numsTempOr, numsTemp[index2 - 1], len, median - index2);
if (index + index2 - 1 == medianSub1) {
return (numsTemp[index2] + numsTemp[index2 - 1]) / 2.0;
} else {
return (numsTemp[index2] + numsTempOr[index0]) / 2.0;
}
} else if (index + index2 == medianSub1) {
int index0 = index;
if(index2 + 1 == numsTemp.length)
return (numsTemp[index2] + numsTempOr[index]) / 2.0;
index = binarySearch(numsTempOr, numsTemp[index2 + 1], len, medianSub1 - index2);
if (index + index2 + 1 == median) {
return (numsTemp[index2] + numsTemp[index2 + 1]) / 2.0;
} else {
return (numsTemp[index2] + numsTempOr[index0]) / 2.0;
}
} else if (index + index2 > median) {
if (lastlt == true) {
numsTemp = nums1;
numsTempOr = nums2;
index2 = len1 >> 1;
len = len2;
lastlt = false;
} else {
index2--;
lastgt = true;
}
} else {
if (lastgt == true) {
numsTemp = nums1;
numsTempOr = nums2;
index2 = len1 >> 1;
len = len2;
lastgt = false;
} else {
index2++;
lastlt = true;
}
}
}
} else { // 奇数的时候
int index2 = len2 >> 1;
int index = 0;
numsTemp = nums2;
numsTempOr = nums1;
len = len1;
for (;;) {
if(numsTemp.length > 0 && index2 < numsTemp.length && index2 > -1)
index = binarySearch(numsTempOr, numsTemp[index2], len, median - index2);
else {
numsTemp = nums1;
numsTempOr = nums2;
index2 = len1 >> 1;
len = len2;
continue;
}
if (index + index2 == median) {
return numsTemp[index2];
} else if (index + index2 > median) {
if (lastlt == true) {
numsTemp = nums1;
numsTempOr = nums2;
index2 = len1 >> 1;
len = len2;
lastlt = false;
} else {
index2--;
lastgt = true;
}
} else {
if (lastgt == true) {
numsTemp = nums1;
numsTempOr = nums2;
index2 = len1 >> 1;
len = len2;
lastgt = false;
} else {
index2++;
lastlt = true;
}
}
}
}
}
public static int binarySearch(int[] nums, int target, int size, int margin) { // 这个数在数组中前面有多少
int begin = 0, end = size;
int temp = 0;
if(nums.length < 1) {
return begin;
}
for (;;) {
temp = (begin + end) >> 1;
if (end > begin) {
if (target > nums[temp]) {
begin = temp + 1;
} else if (target == nums[temp]) {
if(temp == margin) return margin;
while(nums[temp++] == target) {if(temp - 1 == margin) return margin; if(temp == size) {temp ++; break;}};
return --temp;
} else {
end = temp;
}
} else {
return begin;
}
}
}
这是官方的代码
public static double findMedianSortedArrays2(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;
}
//A是小数组
int iMin = 0, iMax = m, halfLen = (m + n + 1) >> 1;
while (iMin <= iMax) {
int i = (iMin + iMax) >> 1;
int j = halfLen - i;
if (i < iMax && B[j-1] > A[i]){
iMin++; // i is too small, j--, i++
} else if (i > iMin && B[j] < A[i-1]) {
iMax--; // i is too big, j++, i--
} 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;
}
官方的逻辑是这样的:
首先将A数组在随机位置i处分成两部分
First let's cut A into two parts at a random position i:
left_A | right_A A[0], A[1], ..., A[i-1] | A[i], A[i+1], ..., A[m-1]
因为A有m个元素,所以有m+1中分组方式(0~m)
已知:
Since A has m elements, so there are m+1 kinds of cutting (i=0∼m).
And we know:
len(left_A)=i,len(right_A)=m−i.
注意:当i=0时,left_A部分是空数组; i=m时,right_A部分是空数组;
Note: when i=0, left_A is empty, and when i=m, right_A is empty.
同理,将B在right_A随机位置j处分成两部分
With the same way, cut B into two parts at a random position j:
left_B | right_B B[0], B[1], ..., B[j-1] | B[j], B[j+1], ..., B[n-1]
将left_A和left_B放入一个区域,同时将right_A和right_B放入另一个区域.并且将这两个区域命名为left_part 和 right_part
Put left_A and left_B into one set, and put right_A and right_B into another set. Let's name them left_partand right_part:
left_part | right_part A[0], A[1], ..., A[i-1] | A[i], A[i+1], ..., A[m-1] B[0], B[1], ..., B[j-1] | B[j], B[j+1], ..., B[n-1]
当要满足下面两个条件时
If we can ensure:
- len(left_part)=len(right_part)
- max(left_part)≤min(right_part)
我们将{A, B}两个数组里面所有的元素分成两个相同大小区域时,一个区域的值总是大于另一区域的值,推出
then we divide all elements in {A,B} into two parts with equal length, and one part is always greater than the other. Then
median=2max(left_part)+min(right_part)
满足这两个条件,只需要满足这两个条件即可:
To ensure these two conditions, we just need to ensure:
学习了
i+j=m−i+n−j (or: m−i+n−j+1)
if n≥m, we just need to set: i=0∼m, j=m+n+12−iB[j−1]≤A[i] and A[i−1]≤B[j]