Median of Two Sorted Arrays
There are two sorted arrays A and B 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)).
解法一:保底做法,O(m+n)復雜度
按照歸並排序的思路,先歸並,再找中間值。
class Solution { public: double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) { int m = nums1.size(); int n = nums2.size(); vector<int> array = merge(nums1, nums2); return ((double)(array[(m+n-1)/2]+array[(m+n)/2]))/2; } vector<int> merge(vector<int> A, vector<int> B) { vector<int> ret; int m = A.size(); int n = B.size(); int i = 0; int j = 0; while(i < m && j < n) { if(A[i] <= B[j]) { ret.push_back(A[i]); i ++; } else { ret.push_back(B[j]); j ++; } } if(i == m) { while(j < n) { ret.push_back(B[j]); j ++; } } if(j == n) { while(i < m) { ret.push_back(A[i]); i ++; } } return ret; } };

解法二:類似二分查找,復雜度O(log(m+n))
這個解法大概思路很簡單,就是A數組的中間元素與B數組的中間元素相比較,從而刪掉較小元素所在數組的前一半和較大元素所在數組的后一半。遞歸下去。
其實要正確實現以上解法還是比較tricky的,因為需要涉及到很多邊界情況,我們來一一解釋:
第一步,我們需要將題目改為尋找第k小的元素findKthSortedArrays。(這里k從1開始計算)
原因在於,如果我們執着於median,那么在刪除一半左右元素形成的子問題中,很難保證仍然是尋找median。可能變為尋找median前一個或者后一個。
(如果仔細思考過這個題就能理解這句話)
改成第k小元素的好處就是,我們可以將刪掉的元素考慮進來,在子問題中不斷改變k的值。
(例如:本來我們需要尋找的median是第5個數,刪掉前面2個數之后,在子問題中就變為尋找第5-2=3個數)
考慮A、B數組總數的奇偶性,就轉化為調用findKthSortedArrays的問題了。
第二部:實現findKthSortedArrays
(一)首先,我們規定A數組比B數組短。
這樣處理的好處在於:我們所需的(k-1)/2位置可能大於某個數組總長度,規定A短之后,只需要考慮超過A的長度,不需要再復制代碼分情況討論了。
這里需要斟酌一下:為什么不是k/2? k/2±1?而是(k-1)/2
我的思考如下:
如果k==1,2,就是需要比較頭兩個元素,因此下標為0
如果k==3,4,就是需要比較第1個元素,因此下標為1
綜上歸納而得。
(二)其次,把特殊情況處理掉。
(1)A數組為空時,即返回B數組第k個元素。
(2)k==1時,即返回A[0]、B[0]中小的那個
(三)接下來再分為兩種情況:
(k-1)/2位置是否超過A數組長度?
(1)若超過,則A數組派出的代表Acandi就是最后元素A[m-1],B派出的代表Bcandi是B[k-m-1]
(a)Acandi==Bcandi,那么正好有k-2個元素比Acandi、Bcandi小,所以第k個元素就是Acandi/Bcandi
(b)Acandi > Bcandi,那么最多只有m-1+k-m-1=k-2個元素比Bcandi小,因此包括Bcandi在內之前的k-m個B數組元素肯定不是第k個數,所以刪去,子問題變為尋找第k-(k-m)個元素
(c)Acandi < Bcandi,那么最多只有m-1+k-m-1=k-2個元素比Acandi小,因此包括Acandi在內之前的整個A數組元素m個元素肯定不是第k個數,所以刪去,子問題變為尋找第k-m個元素
(2)若不超過,則A數組派出的代表Acandi就是A[(k-1)/2],B派出的代表Bcandi是B[(k-1)/2]
(a)Acandi==Bcandi,那么正好有(k-1)/2+(k-1)/2=k-1個元素比Acandi、Bcandi小,所以第k個元素就是Acandi/Bcandi
如果不相等,對於Acandi 、Bcandi本身是否需要取舍就要注意分析了。
經過舉幾個例子簡單分析就很容易發現,k為奇數時,需要保留小的candidate,舍棄大的。
而k為偶數時,需要保留大的candidate,舍棄小的。
(b)Acandi > Bcandi
(b.1)k為奇數,保留Bcandi,刪除Bcandi前面的(k-1)/2個元素,刪除A及A后面的元素(保留A中前(k-1)/2個元素)
(b.2)k為偶數,保留Acandi,刪除Bcandi及前面的(k-1)/2+1個元素,刪除A后面的元素(保留A中前(k-1)/2+1個元素)
(c)Acandi < Bcandi
同(b),略去不贅述了。
class Solution { public: double findKthSortedArrays(int A[], int m, int B[], int n, int k) {//k starts from 1 //make sure A is shorter than B if(m > n) return findKthSortedArrays(B, n, A, m, k); //special case1: A empty if(m == 0) return B[k-1]; //special case2: k==1 (m>0 is guaranteed) if(k == 1) return min(A[0], B[0]); int Acandi, Bcandi; if((k-1)/2 >= m) {//A[(k-1)/2] out of range Acandi = A[m-1]; Bcandi = B[k-m-1]; if(Acandi == Bcandi) return Acandi; else if(Acandi > Bcandi) //for A: no skip //for B: skip the k-m smaller elements (including Bcandi) return findKthSortedArrays(A, m, B+k-m, n-(k-m), k-(k-m)); else //for A: skip the m smaller elements //for B: skip the k-m larger elements return findKthSortedArrays(A+m, 0, B, n-(k-m), k-m); } else { //1,2->index0; 3,4->index1; ... Acandi = A[(k-1)/2]; Bcandi = B[(k-1)/2]; if(Acandi == Bcandi) return Acandi; else if(Acandi > Bcandi) { //for A: skip the larger elements //for B: skip the smaller elements if(k%2 == 1) //keep the smaller candidate, skip the larger return findKthSortedArrays(A, (k-1)/2, B+(k-1)/2, n-(k-1)/2, k-(k-1)/2); else //keep the larger candidate, skip the smaller return findKthSortedArrays(A, (k-1)/2+1, B+(k-1)/2+1, n-((k-1)/2+1), k-((k-1)/2+1)); } else { //for A: skip the smaller elements //for B: skip the larger elements if(k%2 == 1) //keep the smaller candidate, skip the larger return findKthSortedArrays(A+(k-1)/2, m-(k-1)/2, B, (k-1)/2, k-(k-1)/2); else //keep the larger candidate, skip the smaller return findKthSortedArrays(A+(k-1)/2+1, m-((k-1)/2+1), B, (k-1)/2+1, k-((k-1)/2+1)); } } } double findMedianSortedArrays(int A[], int m, int B[], int n) { if((m+n)%2 == 0) {//average of two medians return (findKthSortedArrays(A, m, B, n, (m+n)/2) + findKthSortedArrays(A, m, B, n, (m+n)/2+1))/2; } else { return findKthSortedArrays(A, m, B, n, (m+n)/2+1); } } };

