LeetCode - Median of Two Sorted Arrays

3 篇文章 0 订阅
1 篇文章 0 订阅

问题描述:

There are two sorted arrays A and B 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)).

如果这题不要求时间复杂度为O(log (m+n)),就变得简单了,直接二路归并,返回排序之后的中位数即可(复杂度O(n))。

算法导论上有一个类似的问题:设X[1..n] 和 Y[1..n]为两个数组,每个都包含n个已排好序的数,给出一个求X和Y中所有2n个元素的中位数的、O(lgn)时间的算法。(第二版,9.3-8)

这两个问题是一致的。

对于一个已排序的序列X[1..n],若n为奇数,则中位数为X[n/2+1],也是其低中位数;若n为偶数,则中位数为(X[n/2]+X[n/2+1])/2,其低中位数是x[n/2]。

对于X[1..m] 和 Y[1..n] 合并之后的数列Z,其低中位数不在X中,就是Y中。

假设Z的low median在X中,用lm表示,在X[k]位置,则在X中有k个元素小于等于lm,有m-k个元素大于等于lm。

在合并之后的序列Z中,low median的位置 = ceil((m+n)/2),用mIndex表示。

我们知道,在序列Z中,一定有mIndex 个元素小于等于lm,有(m+n)-mIndex个元素大于等于lm,所以,在Y中,一定有mIndex - k个元素小于等于lm,有n - (mIndex-k)个元素大于等于lm。

因此,我们可以检查:若Y[mIndex-k]<= X[K] <= Y[mIndex-k+1], 则X[k]是我们要找的low median。边界值发生在k=mIndex, mIndex-k=0, 由于没有Y[0],只需比较X[k] <= Y[1]即可。

当low median不是X[k], 则上面的条件就不成立。

若X[k] <Y[mIndex-k] 则说明low median的位置k' > k

若X[k] > Y[mIndex-k+1] 则说明low median的位置k' < k

由以上分析,我们就可以应用binary search去查找在X中是否存在X[k],使得k<=m && k<mIndex && Y[mIndex-k]<=X[k]<=Y[mIndex-k+1] 或者 k<=m && k=mIndex && X[k] <= Y[1]。如果找到这样的k,这是就是我们要找的low median,否则,一定在Y中,对Y做同样的二分搜索来查找k。

每一个二分查找的时间复杂度为O(lgn),最多两个二分查找:O(lgn) + O(lgm) = O(lg(m+n)

class Solution {
public:
    double findMedianSortedArrays(int A[], int m, int B[], int n)
    {
    	int array = 1;
    	int k = findMedian(A, m, B, n, 1, m);
    	if(k<0) { k = findMedian(B, n, A, m, 1, n); array = 2; }
    	if((n+m) % 2)
    	{
    		if(array == 1) return A[k-1];
    		else return B[k-1];
    	} else {
    		int medianIndex = (int)ceil((m+n)/2.0);		
    		if(array == 1)
    		{
    			if(k < m && medianIndex-k < n)
    			{
    				if(A[k] <= B[medianIndex-k]) return (A[k-1] + A[k])/2.0;
    				else return (A[k-1] + B[medianIndex-k])/2.0;
    			} else {
    				if(k >= m) return (A[k-1] + B[medianIndex-k])/2.0;
    				else return (A[k-1] + A[k])/2.0;
    			}
    		} else {
    			if(k < n && medianIndex-k < m)
    			{
    				if(B[k] <= A[medianIndex-k]) return (B[k-1] + B[k])/2.0;
    				else return (B[k-1] + A[medianIndex-k])/2.0;
    			} else {
    				if(k >= n) return (B[k-1] + A[medianIndex-k])/2.0;
    				else return (B[k-1] + B[k])/2.0;
    			}
    		}
    	}
    }
    
    int findMedian(int A[], int m, int B[], int n, int low, int high)
    {
    	int medianIndex = (int)ceil((m+n)/2.0);
    	int k = 0;
    	while(low <= high)
    	{
    		k = (low+high)/2;
    		if(k==medianIndex && (n==0 || A[k-1] <= B[medianIndex - k])) 
    		{
    			return k;
    		}
    		else {
    			if(k>medianIndex)
    			{
    				high = k-1;
    				continue;
    			}
    			if(k<medianIndex && (medianIndex-k-1<n && A[k-1]>=B[medianIndex-k-1]) && (medianIndex-k>=n || A[k-1] <= B[medianIndex-k]))
    			{
    				return k;
    			} else {
    				if(medianIndex-k-1>=n || (medianIndex-k-1>=0 && A[k-1]<B[medianIndex-k-1])) { low = k+1; continue; }
    				else { high = k-1; continue; }
    			}
    		}
    	}
    	return -1;
    }
};


不过,这题有更好的解法,把题目抽象成更普遍的一个问题,寻找两个有序序列第k大值问题。

这里有一个清晰明了的解法: http://blog.csdn.net/yutianzuijin/article/details/11499917


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值