Assume that the number of elements in A and B are both larger than k/2, and if we compare the k/2-th smallest element in A(i.e. A[k/2-1]) and the k-th smallest element in B(i.e. B[k/2 - 1]), there are three results:
(Becasue k can be odd or even number, so we assume k is even number here for simplicy. The following is also true when k is an odd number.)
A[k/2-1] = B[k/2-1]
A[k/2-1] > B[k/2-1]
A[k/2-1] < B[k/2-1]
if A[k/2-1] < B[k/2-1], that means all the elements from A[0] to A[k/2-1](i.e. the k/2 smallest elements in A) are in the range of k smallest elements in the union of A and B. Or, in the other word, A[k/2 - 1] can never be larger than the k-th smalleset element in the union of A and B.
Why?
We can use a proof by contradiction. Since A[k/2 - 1] is larger than the k-th smallest element in the union of A and B, then we assume it is the (k+1)-th smallest one. Since it is smaller than B[k/2 - 1], then B[k/2 - 1] should be at least the (k+2)-th smallest one. So there are at most (k/2-1) elements smaller than A[k/2-1] in A, and at most (k/2 - 1) elements smaller than A[k/2-1] in B.So the total number is k/2+k/2-2, which, no matter when k is odd or even, is surly smaller than k(since A[k/2-1] is the (k+1)-th smallest element). So A[k/2-1] can never larger than the k-th smallest element in the union of A and B if A[k/2-1]Since there is such an important conclusion, we can safely drop the first k/2 element in A, which are definitaly smaller than k-th element in the union of A and B. This is also true for the A[k/2-1] > B[k/2-1] condition, which we should drop the elements in B.
When A[k/2-1] = B[k/2-1], then we have found the k-th smallest element, that is the equal element, we can call it m. There are each (k/2-1) numbers smaller than m in A and B, so m must be the k-th smallest number. So we can call a function recursively, when A[k/2-1] < B[k/2-1], we drop the elements in A, else we drop the elements in B.
We should also consider the edge case, that is, when should we stop?
1. When A or B is empty, we return B[k-1]( or A[k-1]), respectively;
2. When k is 1(when A and B are both not empty), we return the smaller one of A[0] and B[0]
3. When A[k/2-1] = B[k/2-1], we should return one of them
In the code, we check if m is larger than n to garentee that the we always know the smaller array, for coding simplicy.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//C: 40ms | |
class Solution { | |
public: | |
int findKth(vector<int>& nums1, vector<int>& nums2, int k, int s1, int s2){ | |
int n1 = nums1.size()-1-s1+1, n2 = nums2.size()-1-s2+1, n = n1+n2; | |
if(n1>n2) return findKth(nums2, nums1, k, s2, s1); | |
if(n1<=0) return nums2[s2+k]; | |
if(k==0) return min(nums1[s1], nums2[s2]); | |
int a = min((k+1)/2, n1), b = k+1-a; | |
if(nums1[s1+a-1]<=nums2[s2+b-1]){ | |
return findKth(nums1, nums2, k-a, s1+a, s2); | |
}else{ | |
return findKth(nums1, nums2, k-b, s1, s2+b); | |
} | |
} | |
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) { | |
int n1 = nums1.size(), n2 = nums2.size(), n = n1+n2; | |
if(n%2==1){ | |
return findKth(nums1, nums2, n/2, 0, 0); | |
}else{ | |
return (findKth(nums1, nums2, n/2-1, 0, 0)+findKth(nums1, nums2, n/2, 0, 0))/2.0; | |
} | |
} | |
}; |
No comments:
Post a Comment