|
| 1 | +/* |
| 2 | + |
| 3 | + * @Last Modified time: 2016-07-10 14:33:58 |
| 4 | + */ |
| 5 | + |
| 6 | +class Solution { |
| 7 | +public: |
| 8 | + /* |
| 9 | + Divide and Conquer inspired by find k-th number in sorted array. |
| 10 | +
|
| 11 | + The complexity is of course O(log(M+N)). |
| 12 | + Similiar with the following answer except without slicing. |
| 13 | + https://discuss.leetcode.com/topic/6947/intuitive-python-o-log-m-n-solution-by-kth-smallest-in-the-two-sorted-arrays-252ms |
| 14 | + */ |
| 15 | + double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) { |
| 16 | + int len1 = nums1.size(); |
| 17 | + int len2 = nums2.size(); |
| 18 | + int len = len1 + len2; |
| 19 | + if(len & 0x1 == 1){ |
| 20 | + return find_kth(nums1, 0, len1, nums2, 0, len2, (len+1)/2); |
| 21 | + } |
| 22 | + else{ |
| 23 | + return (find_kth(nums1, 0, len1, nums2, 0, len2, (len)/2) + |
| 24 | + find_kth(nums1, 0, len1, nums2, 0, len2, (len)/2+1)) / 2.0; |
| 25 | + } |
| 26 | + } |
| 27 | + |
| 28 | + int find_kth(vector<int>& list1, int begin1, int end1, |
| 29 | + vector<int>& list2, int begin2, int end2, int k){ |
| 30 | + /* |
| 31 | + Find the kth number in two sorted list: list1 , list2 |
| 32 | +
|
| 33 | + Binary search as followers: |
| 34 | + Firstly cut list1 and list2 into two parts by t1 and t2, respectively. |
| 35 | + 1. lis1_left ... list1[t1-th] ... list1_right, |
| 36 | + 2. lis2_left ... list2[t2-th] ... list2_right |
| 37 | + Then compare value of list1[t1-th] and list2[t2-th] in list2. |
| 38 | + Three situations about the relation between list1[t1-th] and list2[t2-th]: |
| 39 | + 1. < Equal the (k-t1)th number in list1_right and list_2 left. |
| 40 | + 2. > Equal the (k-t2)th number in list1_left and list_2 right. |
| 41 | + 3. == Find the k-th number. |
| 42 | + */ |
| 43 | + int len1 = end1 - begin1; |
| 44 | + int len2 = end2 - begin2; |
| 45 | + if(len1 > len2){ |
| 46 | + return find_kth(list2, begin2, end2, list1, begin1, end1, k); |
| 47 | + } |
| 48 | + if(len1 == 0){ |
| 49 | + return list2[begin2+k-1]; |
| 50 | + } |
| 51 | + if(k==1){ |
| 52 | + return min(list1[begin1], list2[begin2]); |
| 53 | + } |
| 54 | + |
| 55 | + int t1 = min(k/2, len1); |
| 56 | + int t2 = k - t1; |
| 57 | + if(list1[begin1+t1-1] < list2[begin2+t2-1]){ |
| 58 | + return find_kth(list1, begin1+t1, end1, list2, begin2, begin2+t2, k-t1); |
| 59 | + } |
| 60 | + else if(list1[begin1+t1-1] > list2[begin2+t2-1]){ |
| 61 | + return find_kth(list1, begin1, begin1+t1, list2, begin2+t2, end2, k-t2); |
| 62 | + } |
| 63 | + else{ |
| 64 | + return list1[begin1+t1-1]; |
| 65 | + } |
| 66 | + } |
| 67 | +}; |
| 68 | + |
| 69 | + |
| 70 | +/* |
| 71 | +[] |
| 72 | +[1] |
| 73 | +[1,3] |
| 74 | +[2] |
| 75 | +[1] |
| 76 | +[2,3,4,5,6] |
| 77 | +[2,3,4] |
| 78 | +[5,6,7] |
| 79 | +*/ |
| 80 | + |
| 81 | + |
| 82 | +/* |
| 83 | +Excellent explanation can be found here: |
| 84 | +https://discuss.leetcode.com/topic/4996/share-my-o-log-min-m-n-solution-with-explanation |
| 85 | +
|
| 86 | +In statistics, the median is used for dividing a set into two equal length subsets, |
| 87 | +that one subset is always greater than the other. |
| 88 | +
|
| 89 | +First let's cut A into two parts at a random position i: |
| 90 | +
|
| 91 | + left_A | right_A |
| 92 | +A[0], A[1], ..., A[i-1] | A[i], A[i+1], ..., A[m-1] |
| 93 | +Since A has m elements, so there are m+1 kinds of cutting( i = 0 ~ m ). |
| 94 | +And we know: len(left_A) = i, len(right_A) = m - i . |
| 95 | +Note: when i = 0 , left_A is empty, and when i = m , right_A is empty. |
| 96 | +
|
| 97 | +With the same way, cut B into two parts at a random position j: |
| 98 | +
|
| 99 | + left_B | right_B |
| 100 | +B[0], B[1], ..., B[j-1] | B[j], B[j+1], ..., B[n-1] |
| 101 | +
|
| 102 | +Put left_A and left_B into one set, and put right_A and right_B into another set. |
| 103 | +Let's name them left_part and right_part : |
| 104 | +
|
| 105 | + left_part | right_part |
| 106 | +A[0], A[1], ..., A[i-1] | A[i], A[i+1], ..., A[m-1] |
| 107 | +B[0], B[1], ..., B[j-1] | B[j], B[j+1], ..., B[n-1] |
| 108 | +
|
| 109 | +If we can ensure: |
| 110 | +
|
| 111 | +1) len(left_part) == len(right_part) |
| 112 | +2) max(left_part) <= min(right_part) |
| 113 | +
|
| 114 | +then we divide all elements in {A, B} into two parts with equal length, |
| 115 | +and one part is always greater than the other. |
| 116 | +Then median = (max(left_part) + min(right_part))/2. |
| 117 | +
|
| 118 | +To ensure these two conditions, we just need to ensure: |
| 119 | +
|
| 120 | +(1) i + j == m - i + n - j (or: m - i + n - j + 1) |
| 121 | + if n >= m, we just need to set: i = 0 ~ m, j = (m + n + 1)/2 - i |
| 122 | +(2) B[j-1] <= A[i] and A[i-1] <= B[j] |
| 123 | +(For simplicity, I presume A[i-1],B[j-1],A[i],B[j] are |
| 124 | +always valid even if i=0/i=m/j=0/j=n . |
| 125 | +I will talk about how to deal with these edge values at last.) |
| 126 | +
|
| 127 | +So, all we need to do is: |
| 128 | +
|
| 129 | +Searching i in [0, m], to find an object `i` that: |
| 130 | + B[j-1] <= A[i] and A[i-1] <= B[j], ( where j = (m + n + 1)/2 - i ) |
| 131 | +
|
| 132 | +When the object i is found, the median is: |
| 133 | + max(A[i-1], B[j-1]) (when m + n is odd) |
| 134 | + or (max(A[i-1], B[j-1]) + min(A[i], B[j]))/2 (when m + n is even) |
| 135 | +*/ |
0 commit comments