【LeetCode】004 Median of Two Sorted Arrays 两个排序数组合并后的中位数

题目:LeetCode 004 Median of Two Sorted Arrays

There are two sorted arrays nums1 and nums2 of size m and n respectively. Find the median of the two sorted arrays. The overall run time complexity should be O(log (m+n)).

题意:给出两组已经排好序的数组,分为有m和n个整数,找到两个数组按顺序合并之后的中位数,使得复杂度为O(log(m+n)).

 

首先需明确中位数的概念,分两种情况,当合并后的数组 C[] 中个数T个,当T为奇数时,C++数组从0开始,第T/2+1个数C[T/2]为中位数,当T为偶数时,中位数为第T/2个数C[T/2-1] 和 第T/2+1个数 C[T/2]的和的一半。有下面三种思路。

思路一:利用C++最简单的思路,涉及到排序用快排sort,将两个数组合并后排序找到中位数,复杂度为O((n+m)log(n+m))。

思路二:利用已知的两个数组都有序这个特点,顺次合并排序,复杂度为O(m+n)。另外网上有一种方法也是O(m+n)的算法,用两个指针分别记录个数然后找到中位数,我尝试了一下发现边界条件太多放弃了。

我的代码如下:

class Solution {
public:
    double findMedianSortedArrays(vector<int>& a, vector<int>& b) {
        vector<int> c;    
		int m = a.size(), n = b.size(), i = 0, j =0;
		while(i < m && j < n)
		{
			if(a[i] < b[j])
				c.push_back(a[i++]);
			else if(a[i] > b[j])
				c.push_back(b[j++]);
			else
			{
				c.push_back(a[i++]);
				c.push_back(b[j++]);
			}
		}
		while(i < m) c.push_back(a[i++]);
		while(j < n) c.push_back(b[j++]);
		int t = m + n;
		if(t&1) return c[t/2];
		return 0.5*(c[t/2]+c[t/2-1]);
    }
};

 

思路三:http://blog.csdn.net/doc_sgl/article/details/13081925

这个思路是将求中位数转化成了求两个排好序的数组的第K小的数。求中位数,即令K=T/2 或 K=T/2+1即可。

首先,两个排好序的数组A[], B[]分别有m和n个,求第k小的数。假设合并后的数组为C[],个数为m+n。

其次,要明确一个规律。将 k 分成两部分 k = pa + pb,也就是说合并后的数组的前k个数是由数组A[]的前pa个数A[0]...A[pa-1]和数组B[]的前pb个数B[0]...B[pb-1]组成。

比较数组A[]中的第pa个数和数组B[]中的第pb个数。

(1)如果A[pa-1] == B[pb-1],那么合并之后刚刚好第k=pa+pb个数即为A[pa-1]或者B[pb-1]。(递归终点1)

(2)如果A[pa-1] < B[pb-1],那么数组A中的前pa个数一定不会是数组C的第k个数。证明很简单,反证,假设A[pa-1]为第k个数,则A中有pa-1个数在C[k-1]前面,因为A[pa-1]<B[pb-1],B中之多有pb-1个数在C[k-1]前面,那么C中最多有(pa-1)+(pb-1)=pa+pb-2=k-2个数在C[k-1]前面,坐标从0开始,矛盾。

这样,我们就可以把数组A中的前pa个数删掉,求A[pa]..A[m-1] 与数组B合并之后的第k-pa小的数。

(3)同理,如果A[pa-1] > B[pb-1],那么数组B中的前pb个数一定不会是数组C的第k个数。

对于把k拆分成两部分,最简单的思路即二分,取 pa = k/2,但是有可能m < k/2,则此时取pa = m。

这样我们就将这个问题变成了一个同类的子问题,可以用递归的思路来解。递归的话,就需要考虑递归的终点:

(1)如果A或者B为空,则直接返回B[k-1]或者A[k-1];

(2)如果k为1,我们只需要返回A[0]和B[0]中的较小值;

(3)如果A[k/2-1]=B[k/2-1],返回其中一个;

思路看懂了,但是我自己的样例一直都过不了,递归还是学的不好,在一层层递归下去进入子问题时,我懂,中间调试结果也是对的,但是到达递归终点返回之后,进入上一层,我就搞不懂了。

 

终于过了,原因在于,子问题没有返回值。标红的三个地方出错,递归到达终点之后回返回上一层递归的函数,如果是有返回值的递归函数,加上return会在每一层递归的时候直接函数结束再次返回到上上一层的递归

由于每次删掉前面一半的元素时利用了数组首地址移动,所以写成C的代码如下:

int findKth(int a[], int m, int b[], int n, int k)
{
	int pa, pb;
	if(m > n) 
		return findKth(b, n, a, m, k);
	if(m == 0) 
		return b[k-1];
	if(k == 1) 
		return a[0] < b[0] ? a[0] : b[0];

	pa = k/2 < m ? k/2 : m; 
	pb = k-pa;

	if(a[pa-1] < b[pb-1])
		return findKth(a+pa, m-pa, b, n, k-pa);
	else if(a[pa-1] > b[pb-1])		
		return findKth(a, m, b+pb, n-pb, k-pb);
	return a[pa-1];
}

double findMedianSortedArrays(int *nums1, int m, int *nums2, int n) 
{
    int t = m+n;
	if(1&t) return findKth(nums1, m, nums2, n, t/2+1);
	return 0.5*( findKth(nums1, m, nums2, n, t/2+1) + findKth(nums1, m, nums2, n, t/2) );
	
}

  

 然后跟同学请教发现如果是C++利用vector没有办法直接利用数组首地址移动时,就需要记录vector<int>的开始位置,然后就能O(1)访问vector了。代码如下:

class Solution {
public:
	int findKth(vector<int> a, int m, vector<int> b, int n, int k)
	{
		int lena = a.size() - m, lenb = b.size() - n;
		if(lena > lenb) return findKth(b, n, a, m, k);
		if(lena == 0) return b[n+k-1];
		if(k == 1) return min(a[m], b[n]);
		int pa = min(k/2, lena), pb = k - pa;
		int ida = m + pa - 1, idb = n + pb - 1;
		if(a[ida] < b[idb]) return findKth(a, m+pa, b, n, k-pa);
		else if(a[ida] > b[idb]) return findKth(a, m, b, n+pb, k-pb);
		return a[ida];
	}
	double findMedianSortedArrays(vector<int>& a, vector<int>& b) 
	{
		int t = a.size() + b.size();
		if(0x1&t) return findKth(a, 0, b, 0, t/2+1);
		return 0.5*(findKth(a, 0, b, 0, t/2) + findKth(a, 0, b, 0, t/2+1));
	}
};

  

转载于:https://www.cnblogs.com/kathyrine/p/4605187.html

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值