题目: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; } }