4.寻找两个正序数组的中位数
- 设两个数组长度分别为m,n
- 对第一个数组先取前i个数,第二个数组取前(m+n+1)/2-i个数字,组成leftpart,其余剩下的组成rightpart
- 可以得到len(leftpart)>=len(rightpart)且,当m+n为偶数时候相等,奇数时候len(leftpart)=len(rightpart)+1
- 如果满足,min(rightpart)>=max(leftpart),那么显然此时答案两种可能
- m+n为偶数,答案是(min(rightpart)+max(leftpart))/2
- m+n为奇数,答案是max(leftpart)
可以通过二分查找获得。过程如下:
- 设lpi为第一个数组的第i个数字,rpi为第一个数组的第i+1个数字
- 设lpj为第二个数组的第j个数字,rpj为第二个数组的第i+1个数字
当我们寻求使用二分寻求解空间的时候,设当前区间为(left,right),i=(left+right)/2,j=(m+n+1)/2-i;
此时若lpi<=rpj:
-
i必须向右移动。简单理解就是i小了,解空间在右边。证明如下
此时易得lpi<=rpi,lpi<=rpj,lpj<=rpj
1. 若此时lpj<=rpi,此时为答案即可记录。 2. 此时若lpj>rpi,证明i需要增大,j需要减小,于是就是解空间的i在右边
同理可证得lpi>rpj的情况得向左移动。
tips:需要注意对边界的处理,以及编程时候的定义。
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
if (nums1.length > nums2.length) return findMedianSortedArrays(nums2, nums1);
int m = nums1.length, n = nums2.length;
int m1 = 0, m2 = 0;
int left = 0, right = m;
while (left <= right) {
int i = (left + right) / 2;
int j = (m + n + 1) / 2 - i;
int lpi = i == 0 ? Integer.MIN_VALUE : nums1[i - 1];
int rpi = i == m ? Integer.MAX_VALUE : nums1[i];
int lpj = j == 0 ? Integer.MIN_VALUE : nums2[j - 1];
int rpj = j == n ? Integer.MAX_VALUE : nums2[j];
if (lpi <= rpj) {
m1 = Math.max(lpi, lpj);
m2 = Math.min(rpi, rpj);
left = left + 1;
} else right = right - 1;
}
return (m + n) % 2 == 0 ? (m1 + m2) / 2.0 : m1;
}