题目链接
Generalize 的问题就是在两个 sorted 的 array 里找第k个大的数。我们假设 x <= k,我们取第一个 array 的第 x 个数,取第二个 array 的 第 k - x个数。如果:
- A[x] <= B[k - m] 那么 A 中前 x个数不可能是答案
- A[x] > B[k - m] 那么 B 中前 k - x个数不可能是答案
那么对于 x我们每次可以取 k / 2 和 A.length 中的较小值。当 k / 2 > A.length 时,我们会把A全部砍掉,但是这并不影响时间复杂度,因为当我们不需要考虑A时,直接return B的第k大的数就可以了。时间复杂度 O(log k) = O(log (m + n)),因为我们每次砍掉k的一半的数。代码如下:
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
class Solution { | |
public: | |
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) { | |
int len1 = nums1.size(), len2 = nums2.size(), k = (len1 + len2 + 1) / 2; | |
if((len1 + len2) % 2) | |
return findKth(nums1, nums2, 0, 0, k); | |
else | |
return (findKth(nums1, nums2, 0, 0, k) + findKth(nums1, nums2, 0, 0, k + 1)) / 2.0; | |
} | |
private: | |
int findKth(vector<int>& nums1, vector<int>& nums2, int lo1, int lo2, int k) | |
{ | |
int len1 = static_cast<int>(nums1.size()) - lo1, len2 = static_cast<int>(nums2.size()) - lo2; | |
if(len1 > len2) | |
return findKth(nums2, nums1, lo2, lo1, k); | |
if(!len1)return nums2[lo2 + k - 1]; | |
if(k == 1)return min(nums1[lo1], nums2[lo2]); | |
int i = min(k / 2, len1), j = k - i; | |
if(nums1[lo1 + i - 1] >= nums2[lo2 + j - 1]) | |
return findKth(nums1, nums2, lo1, lo2 + j, k - j); | |
else | |
return findKth(nums1, nums2, lo1 + i, lo2, k - i); | |
} | |
}; |
第二种不好 generalize,每次我们砍掉较短的 array 的 (len - 1) / 2,的长度,对应的长的 array 我们也砍掉这么多,那么可以保证中位数还是砍掉后的两个 array 的中位数,这么一直做直到较短的 array 剩下 一个元素或者两个元素,即有两种base case,时间复杂度 O(log min (m , n))。代码如下:
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
public class Solution { | |
private double min(double a, double b){ | |
return a >= b? b: a; | |
} | |
private double max(double a, double b){ | |
return a >= b? a: b; | |
} | |
private double findMedian(int[] A, int lo, int hi){ | |
int mid = (lo + hi) / 2; | |
int len = hi - lo + 1; | |
return len % 2 == 0? (A[mid] + A[mid + 1]) / 2.0: A[mid]; | |
} | |
private double findMedianBaseCaseOne(int[] A, int lo, int hi, double med1){ | |
double med2 = findMedian(A, lo, hi); | |
int len = hi - lo + 1; | |
int mid = (lo + hi) / 2; | |
if (len % 2 == 0){ | |
if (med1 > med2) | |
return min(med1, A[mid + 1]); | |
else if (med1 < med2) | |
return max(med1, A[mid]); | |
else | |
return med1; | |
}else { | |
int a = mid - 1 < lo? Integer.MIN_VALUE: A[mid - 1]; | |
int b = A[mid]; | |
int c = mid + 1 > hi? Integer.MAX_VALUE: A[mid + 1]; | |
if (med1 > med2) | |
return (b + min(med1, c)) / 2.0; | |
else if (med1 < med2) | |
return (b + max(med1, a)) / 2.0; | |
else | |
return med1; | |
} | |
} | |
private double findMedianBaseCaseTwo(int[] A, int lo, int hi, int left, int right){ | |
double med2 = findMedian(A, lo, hi); | |
int len = hi - lo + 1; | |
int mid = (lo + hi) / 2; | |
if (len % 2 == 0){ | |
int a = mid - 1 < lo? Integer.MIN_VALUE: A[mid - 1]; | |
int b = A[mid], c = A[mid + 1]; | |
int d = mid + 2 > hi? Integer.MAX_VALUE: A[mid + 2]; | |
if (right <= b) | |
return (max(right, a) + b) / 2.0; | |
else if (left <= b) | |
return (min(right, c) + b) / 2.0; | |
else if (left >= c) | |
return (min(left, d) + c) / 2.0; | |
else if (right >= c) | |
return (left + c) / 2.0; | |
else | |
return (left + right) / 2.0; | |
} else { | |
int a = A[mid - 1]; | |
int b = A[mid]; | |
int c = A[mid + 1]; | |
if (left >= b) | |
return min(c, left); | |
else if (right <= b) | |
return max(right, a); | |
else | |
return b; | |
} | |
} | |
private double findMedianRecursion(int[] A, int lo1, int hi1, int[] B, int lo2, int hi2){ | |
int len1 = hi1 - lo1 + 1; | |
int len2 = hi2 - lo2 + 1; | |
double med1 = findMedian(A, lo1, hi1); | |
double med2 = findMedian(B, lo2, hi2); | |
if (len1 == 1) | |
return findMedianBaseCaseOne(B, lo2, hi2, A[lo1]); | |
if (len2 == 1) | |
return findMedianBaseCaseOne(A, lo1, hi1, B[lo2]); | |
if (len1 == 2) | |
return findMedianBaseCaseTwo(B, lo2, hi2, A[lo1], A[hi1]); | |
if (len2 == 2) | |
return findMedianBaseCaseTwo(A, lo1, hi1, B[lo2], B[hi2]); | |
int cutLen = len1 >= len2? len2: len1; | |
cutLen = (cutLen - 1) / 2; | |
if (med1 > med2) | |
return findMedianRecursion(A, lo1, hi1 - cutLen, B, lo2 + cutLen, hi2); | |
else if (med1 < med2) | |
return findMedianRecursion(A, lo1 + cutLen, hi1, B, lo2, hi2 - cutLen); | |
else | |
return med1; | |
} | |
public double findMedianSortedArrays(int A[], int B[]) { | |
int len1 = A.length; | |
int len2 = B.length; | |
if (len1 == 0 && len2 == 0) | |
return 0; | |
if (len1 == 0) | |
return findMedian(B, 0 ,len2 - 1); | |
if (len2 == 0) | |
return findMedian(A, 0, len1 - 1); | |
return findMedianRecursion(A, 0, len1 - 1, B, 0, len2 - 1); | |
} | |
} |
No comments:
Post a Comment