LeetCode 4. Median of Two Sorted Arrays

#include<iostream>
#include<vector>
#include<algorithm>

using namespace std;

//假設有兩個數組A和B,其長度分別爲m,n,我們假設n>=m,
//那麼我們先做這樣的分析:
//將數組A和B分別在位置i和位置j切分爲兩部分:
//		left_part     |      right_part
//A[0],A[1],...,A[i-1]|A[i],A[i+1],...,A[m-1]
//B[0],B[1],...,B[j-1]|B[j],B[j+1],...,B[n-1]
//由於A和B在合併之前,各自是已經排序好的
//所以找合併後的中位數,就是找如上的切分的情況下,
//使得:(1)length(left_part) == length(right_part) (當 m+n 的長度爲偶數時)
//		  length(left_part) == length(right_part)+1 (當 m+n 的長度爲奇數時)
//     (2)max(left_part) <= min(right_part)
//這樣,中位數爲:
//     (1)當 m+n 爲偶數時,(max(A[i-1],B[j-1])+min(A[i]+B[j]))/2
//	   (2)當 m+n 爲奇數時, max(A[i-1],B[j-1]) (即只可能在A[i-1]和B[j-1]中產生,
//		 不可能在A[i]和B[i]中產生,因爲在上面我們已經保證了,當 m+n 的長度爲偶數時,
//		 左邊部分的長度比右邊部分的長度大1)
//那麼,從上訴的條件中,我們可以推導出,即需要找出這樣一個i,使得:
//	   (1)i+j == m-i+n-j (or: i+j == m-i+n-j+1) ==> j = (m+n+1)/2-i (0 <= i <= m)
//	   (2)B[j-1]<=A[i] && A[i-1]<=B[j]
//這樣,我們便可以使用二分查找(left,i,right),對應的 time complexity 爲: O(log(min(m,n)))
// 在二分查找的過程中,我們會遇到如下3種情況:
//(1)A[i]<B[j-1], 對應的措施爲: left=i+1;
//(2)A[i-1]>B[j], 對應的措施爲:right=i-1;
//(3)B[j-1]<=A[i] && A[i-1]<=B[j], 剛好找到滿足條件的i值,返回即可。
//當然,在上述的查找過程中,我們需要保證 索引i 和 索引j 不能越界,也即是說:
//條件組:(1)i+j == m-i+n-j (or: i+j == m-i+n-j+1) ==> j = (m+n+1)/2-i (0 <= i <= m)
//	      (2)B[j-1]<=A[i] && A[i-1]<=B[j])
//即轉化爲,在[0...m](注意,這裏右邊界是m,而不是m-1,這是因爲把一個長度爲m: A[0...m-1]
//切分爲兩段的方式有 m+1 種:當 在A[0]前切一刀時,得到的左邊部分爲 空, 右邊部分爲 A ;
//在 A[m-1] 後切一刀,得到的左邊部分爲 A,右邊部分爲 空),找到一個 索引i,使得:
// (i==0||i==m||B[j-1]<=A[i]) && (j==0||j==n||A[i-1]<=B[j]) ,其中 j = (m+n+1)/2-i, n>=n
// 在上述的式子左邊部分中隱含着: 當 0<i<m 時,能夠通過 j=(m+n+1)/2-i 推導出  n > j > 0
//
// 綜上所述,在二分查找的循環中,遇到的情況有且僅有如下3種:
//
//if      (1) j>0 && i<m && A[i]<B[j-1] ==> i 過小, left = i+1;
//else if (2) i>0 && j<n && A[i-1]>B[j] ==> i 過大, right = i-1;
//else    (3) (i==0||i==m||B[j-1]<=A[i]) && (j==0||j==n||A[i-1]<=B[j]) ==> 符合條件,停止,返回 i ;
class Solution {
public:
	double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
		int m = nums1.size(), n = nums2.size();
		if (m > n)return findMedianSortedArrays(nums2, nums1);
		int left = 0, right = m;
		int i, j, mNum1, mNum2;
		while (left <= right) {
			i = ((right - left) >> 1) + left;
			j = ((m + n + 1) >> 1) - i;
			if (j > 0 && i < m&&nums1[i] < nums2[j - 1])left = i + 1;
			else if (i > 0 && j<n&&nums1[i - 1]>nums2[j])right = i - 1;
			else {
				if (i == 0) mNum1 = nums2[j - 1];
				else if (j == 0)mNum1 = nums1[i - 1];
				else mNum1 = max(nums1[i - 1], nums2[j - 1]);
				break;
			}
		}
		if (((m + n) & 1))return mNum1;
		else if (i == m)mNum2 = nums2[j];
		else if (j == n)mNum2 = nums1[i];
		else mNum2 = min(nums2[j], nums1[i]);
		return (mNum1 + mNum2) / (double)2;
	}
};


/*
* 轉化爲找第k大的數
*
class Solution {
public:
	double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
		int m = nums1.size();
		int n = nums2.size();
		int total = m + n;
		if (total & 0x1)
			return findKth(nums1, 0, m, nums2, 0, n, total / 2 + 1);
		else
			return (findKth(nums1, 0, m, nums2, 0, n, total / 2)
				+ findKth(nums1, 0, m, nums2, 0, n, total / 2 + 1)) / 2;
	}

	double findKth(const vector<int>& a, int ast, int m, const vector<int>& b, int bst, int n, int k) {
		if (m > n)
			return findKth(b, bst, n, a, ast, m, k);
		if (m == 0)return b[bst + k - 1];
		if (k == 1)return min(a[ast], b[bst]);
		// divide k into two parts
		int pa = min(k / 2, m), pb = k - pa;
		if (a[ast + pa - 1] < b[bst + pb - 1])
			return findKth(a, ast + pa, m - pa, b, bst, n, k - pa);
		else if (a[ast + pa - 1] > b[bst + pb - 1])
			return findKth(a, ast, m, b, bst + pb, n - pb, k - pb);
		else return a[ast + pa - 1];
	}
};
*/
int main(int argc, char **argv) {
	vector<int> nums1{ 1,2 };
	vector<int> nums2{ 3,4 };
	Solution A;
	cout << A.findMedianSortedArrays(nums1, nums2) << endl;
	cin.get();
	return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章