题目: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)).
翻译:nums1和nums2是两个已经排好序的数组(升序),求这两个数组合并并排序之后所得数组的中位数。
如,num1 [1,2,3] num2 [2,3,4] 合并 [1,2,2,3,3,4] 中位数为(2+3)/2 = 2.5
如,num1 [1,2,3] num2 [2,3] 合并 [1,2,2,3,3] 中位数为 2
解法1:O(m+n)
该方法是最直观的解法——将两个数组合并为一个新的数组,直接求其中位数。
解法2:O(log (m+n))
该解法的关键是利用如下结论——两个有序数组A,B,若A[K/2-1]<=B[K/2-1],则A[0]~A[K/2-1]一定在合并并排序后的数组的第k个数之前。可用反证法证明。如,A [1,2,3],B[2,3,4] 合并 [1,2,2,3,3,4],令上述结论中的K=4,A[K/2-1]=A[1] =2,B[K/2-1]=B[1]=3,A[1]<B[1],可以看出,此时A的前两个数1,2均在合并后的数组的第四个数之前。
解法3:O(min(m,n))
该解法的关键是利用如下结论——两个有序数组A,B,合并并排序后得到的数组为C,若有一个数X使C[K]=A[X]或者C[K]=B[K-X-1](K为小于A,B元素和的任意值),当且仅当A[X+1]>=B[K-X-1]且B[K-X]>=A[X]。
证明(必要性易证,下面只证明充分性,即如何由“A[X+1]>=B[K-X-1]且B[K-X]>=A[X]”推出“[K]=A[X]或者C[K]=B[K-X-1]”):
由A[X+1]>=B[K-X-1]可推得B[K-X-1]<=C[K](用反证法可证:若B[K-X-1]>C[K],则必有(X+1)+(K-X-1+1)>(K+1)即K+1>K+1,显然不成立)。
由B[K-X]>=A[X]可推得A[X]<=C[K](同样用反证法证明)。
此时得到A[X]<=C[K]且B[K-X-1]<=C[K],又由于A,B均为有序数组,得证C[K]=A[X]或者C[K]=B[K-X-1]
方法3源码如下:
double findkth(int* nums1, int nums1Size, int* nums2, int nums2Size, int kth)
{//FinalIndex_nums1,FinalIndex_nums2从0开始;kth based on 0(从0开始,不知道英文是不是这么讲。。)
#define ifn (int)0x7fffffff
#define nifn (int)0x80000000
#define A(i) (i>nums1Size-1?ifn:(i<0?nifn:nums1[i]))
#define B(i) (i>nums2Size-1?ifn:(i<0?nifn:nums2[i]))
if (nums1Size > nums2Size)
return findkth(nums2, nums2Size, nums1, nums1Size, kth);
if (nums1Size == 0)
return nums2[kth];
//nums1 is shorter than nums2 below
int x = 0, l = 0, r = 0;
if (kth > (nums1Size - 1))
r = nums1Size - 1;
else
r = kth;
bool Nums1beforeKth = false;
while (l <= r)
{
x = (l + r) >> 1;//即x = (l + r)/2;
double t1 = A(x + 1);
double t2 = B(kth - x - 1);
if (A(x+1) < B(kth - x - 1))
l = x + 1;
else if (B(kth - x) < A(x))
r = x - 1;
else
{
Nums1beforeKth = true;
if (nums1[x]>nums2[kth - x - 1])
{
return nums1[x];
}
else
{
return nums2[kth - x - 1];
}
}
}
if (!Nums1beforeKth)
{
return nums2[kth];
}
}
double findMedianSortedArrays(int* nums1, int nums1Size, int* nums2, int nums2Size)
{//log(min(m,n))
bool odd = false;
if ((nums1Size + nums2Size) % 2 == 1)
odd = true;
if (odd)
{
return findkth(nums1, nums1Size, nums2, nums2Size, (nums1Size + nums2Size) / 2);
}
else
{
double mid_1 = findkth(nums1, nums1Size, nums2, nums2Size, (nums1Size + nums2Size) / 2);
double mid_2 = findkth(nums1, nums1Size, nums2, nums2Size, ((nums1Size + nums2Size) / 2) - 1);
return (mid_1 + mid_2) / 2;
}
}