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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值