4. Median of Two Sorted Arrays(二分查找)

Description:

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)).

 

Discuss:

参考本题排名第一的discuss的思路如下,最终时间复杂度为 O ( log(min( m , n ) )

 

1.分析问题:

首先理解中位数是以什么,在统计学中,中位数是用来把一个集合分成两个长度相等的子集,并且一个子集大于另一个子集,即一个子集中的任意元素大于另一个子集中的任意元素。

 

这里有两点条件,长度相等,任意元素大于。所以列出下面的模型,为了后面便于思考

                 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]

其中

mA数组长度

nB数组长度

iA数组的分割点,一共有m+1个分割点,i=0,1,2...m

jB数组的分割点,一共有n+1个分割点,j=0,1,2...n

 

2.找出判断条件:

根据中位数的性质,得出判断条件为:

(1) len(left_part) == len(right_part) 

(2) max(left_part) <= min(right_part)

 

首先设置n>=m,原因如下:

即设置数组A为长度较小的数组。如果数组A的长度大于数组B的长度,A的分割点无法到取到靠后的位置,因为可能会使leftA的长度大于rightA+lenB的长度。这样i就可以任意取,i , j 结果都为正,我们只要考虑 i的范围即可,有序数组的查找显然后面可以使用二分法。

 

继续推导判断条件,有两种情况:

<1> m+n为偶数时,中位数是中间两数之和,若想找到正确的i,应该有:

         (1) i + j == m - i + n - j 

         (2) B[j-1] <= A[i] and A[i-1] <= B[j]

   最后的结果为 (max(A[i-1], B[j-1]) + min(A[i], B[j]))/2

<2> m+n为奇数时,中位数是中间的一个数,把中间的数归到左半部分,则有:

         (1) i + j == m - i + n - j + 1

         (2) B[j-1] <= A[i] and A[i-1] <= B[j]

   这时最后的结果为 max(A[i-1], B[j-1])

 

我们之前设置过i是可以任意取值的,于是有j=(m+n)/2-i,并且其中j > 0

m+n为偶数时,(m+n)/2==(m+n+1)/2,所以以上两种情况的判断条件可以合并,但两种情况的中位数结果是不同的,于是得到最终判断条件为:

          (1) i = 0 ~ m, j = (m + n + 1)/2 - i 

          (2) B[j-1] <= A[i] and A[i-1] <= B[j]

 

3.确定循环过程:

根据上面的特点,可以对i使用二分法查找,并且根据之前对奇偶情况结果的讨论,需要保存left_part_maxright_part_min

 

设置imin=0,imax=m,i=(imin+imax)/2,则对于一个给定的i,有如下几种情况:

 

搜索过程:

<1> B[j-1] > A[i] && i < m , 需要增加i,令imin=i+1

<2> A[i-1] > B[j] && i > 0 , 需要减小i,令imax=i-1

备注:(i小于m时,因为m<=n,j若等于0,右半部分元素会过多,所以j一定大于0)

           (i大于0时,因为m<=n,j若等于n,左半部分元素会过多,所以j一定小于n)

 

判定结果,有以下几种解的情况:

<1>i == 0 && j != n

<2>i == 0 && j == n

<3>i == m && j = 0

<4>i == m && j ==0

<5>0 < i < m && B[j-1] <= A[i] && A[i-1] <= B[j]

备注:如果在二分的过程中,i取到边界0m,显然已进行到二分法循环的边界,所以这时i一定是最后的正确的取值。每一步都需要设置对应的left_part_maxright_part_min

 

设置left_part_maxright_part_min

边界情况,当i=0,i=m,j=0,j=n,即某一part中只含有单个数组的元素,则这部分part的最值就是被分到这个part的数组中的元素的最值。于是有如下对应的part的最值

<1>leftmax=B[j-1] rightmin=min(A[i],B[j])

<2>leftmax=B[j-1] rightmin=A[i]

<3>leftmax=max(A[i-1],B[j-1]) rightmin=B[j]

<4>leftmax=A[i-1] rightmin=B[j]

<5>leftmax=max(A[i-1],B[j-1]) rightmin=min(A[i],B[j])

 

综上所述,可以用类似笛卡尔积的形式,以两个if-else语句块分别表达出leftmax和rightmin结果:

if(i==0)

     leftmax=B[j-1]

else if(j==0)

     leftmax=A[i-1]

else

     leftmax=max(A[i-1],B[j-1]);


if(i==m)

     rightmin=B[j]

else if(j==n)

     rightmin=A[i]

else

     rightmin=min(A[i],B[j])


时间复杂度:

二分法的时间复杂度为O( logx ),显然本题的时间复杂度为O ( log(min( m , n ) )

 

代码:

double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
	if(nums1.size()>nums2.size()){
		vector<int> temp=nums1;
		nums1=nums2;
		nums2=temp;
	}
	int m=nums1.size(),n=nums2.size();
	int imin=0,imax=m;
	int leftmax,rightmin;
	while (imin<=imax)
	{
		int i=(imin+imax)/2;
		int j=(m+n+1)/2-i;
		if(i>0&&nums1[i-1]>nums2[j])//j<n
			imax=i-1;//decrease i
		else if(i<m&&nums1[i]<nums2[j-1])//j>0
			imin=i+1;//increase i
		else{
			if(i==0)
				leftmax=nums2[j-1];
			else if(j==0)
				leftmax=nums1[i-1];
			else
				leftmax=max(nums1[i-1],nums2[j-1]);

			if((m+n)%2==1)
				return leftmax;
                
			if(i==m)
				rightmin=nums2[j];
			else if(j==n)
				rightmin=nums1[i];
			else
				rightmin=min(nums1[i],nums2[j]);
                
			return (leftmax+rightmin)/2.0;
		}
	}
}


 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值