leetcode 4. 两个排序数组的中位数

4. 两个排序数组的中位数

随机一题


给定两个大小为 m 和 n 的有序数组 nums1 和 nums2 

请找出这两个有序数组的中位数。要求算法的时间复杂度为 O(log (m+n)) 。

你可以假设 nums1 和 nums2 不同时为空。

示例 1:

nums1 = [1, 3]

nums2 = [2]

中位数是 2.0

示例 2:

nums1 = [1, 2]

nums2 = [3, 4]

中位数是 (2 + 3)/2 = 2.5

思路:

这个可以理解为寻找两个有序数组的第k位数字,采用二分查找的方式

看到这个题的第一反应是把两个数组遍历一遍并组合到一个数组中,取中位数就很简单了。这样做的时间复杂度为O(m+n),可还是能通过测试,可能lintcode没有检测时间复杂度?

时间复杂度为O(m+n)的方法是在别人的方法之上,修修补补才能放在这个题目下运行起来的。。。心疼自己的智商

本题从时间复杂度来看就是采用二分法,该方法的核心是将原问题转变成一个寻找第k小数的问题(假设两个原序列升序排列),这样中位数实际上是第(m+n)/2小的数。所以只要解决了第k小数的问题,原问题也得以解决。因为A和B都是升序的,理想情况下假设A和B的个数都大于k/2(这里的k就是两个数组合起来的中位数(m+n)/2)。首先比较A[k/2-1]和B[k/2-1]

情况一:A[k/2-1]<B[k/2-1],则A[0]-A[k/2-1]的值必定在合并后的前k个元素中,换言之合并后的中位数第k个元素不可能出现在A[0]-A[k/2-1]这个区间。因为如果中位数出现在A[0]-A[k/2-1]这个区间,而且A[k/2-1]<B[k/2-1]表示这个中位数之后(k=(m+n)/2)有超过n-k/2+m-k/2即(m+n)/2个元素,这显然不符合中位数的定义,所以可以将A[0]-A[k/2-1]范围的元素抛弃,并将要寻找的中位数减去抛弃元素的个数。

二:当A[k/2-1]<B[k/2-1]时同上,抛弃B的部分元素。

三:当A[k/2-1]=B[k/2-1]时,说明已经找到了中位数,返回其中任意一个即可。

对于一些边界情况,当A或者B为空时,直接返回不为空的数组中位数;

当k=1时(因为每次递归都会改变中位数的值),返回A和B中第一个元素较小者

因为这道题给的是向量vector的形式而不是数组,所以为了表示下标可能代码有点凌乱,下为代码

 

class Solution {
public:
    /**
     * @param A: An integer array.
     * @param B: An integer array.
     * @return: a double whose format is *.5 or *.0
     */
    double findMedianSortedArrays(vector<int> A, vector<int> B) {
	  int m=A.size(),n=B.size();
	  int s=m+n;
	  if(s&0x01)//真为奇数
		  return findKth(A,B,0,0,m,n,s/2+1);
	  else
	  {
		  double a=findKth(A,B,0,0,m,n,s/2);
		  double b=findKth(A,B,0,0,m,n,s/2+1);
		  return (a+b)/2;
	  }
		 // return (findKth(A,B,0,0,m,n,s/2)+findKth(A,B,0,0,m,n,s/2+1))/2;
 
    }
private:
	double findKth(vector<int> A, vector<int> B,int start1,int start2,int m,int n,int k)//start1,start2代表每个vector起始的下标;m,n代表各vector剩余的元素个数
	{
		//保证A是较短的数组,因为会出现数组长度小于k/2的情况,所以根据较小数组来定另一个数组
		if(m>n)//m代表A的长度,n代表B的长度
			return findKth(B,A,start2,start1,n,m,k);
		if(m==0)//m=0即代表数组arr1中已经没有元素了,所以中位数从B中找
			return B[start2+k-1];//下标加start2的原因是不一定是从下标0开始,可能下标0到start2的元素已经被抛弃
		if(k==1)
			return min(A[start1],B[start2]);
		int x=min(k/2,m),y=k-x;//记录两组中位数下标
		if(A[start1+x-1]<B[start2+y-1])
			return findKth(A,B,start1+x,start2,m-x,n,k-x);//start1+x表示舍弃x个不可能的元素,m-x表示将x个元素
		                                                  //剔除掉数组,k-x表示这x个元素已经被剔除,接下来中位数表示第k-x个元素
		else
			if(A[start1+x-1]>B[start2+y-1])
				return findKth(A,B,start1,start2+y,m,n-y,k-y);//start2+y表示舍弃y前的元素
 
			else
				return A[start1+x-1];
 
	}//本题舍弃的均为各自数组所选下标之前的元素
};

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值