LeetCodeLeetCode 两个排序数组的中位数问题

有两个大小为 m 和 n 的排序数组 nums1 和 nums2 。

请找出两个排序数组的中位数并且总的运行时间复杂度为 O(log (m+n)) 。

示例 1:

nums1 = [1, 3]
nums2 = [2]

中位数是 2.0
 

示例 2:

nums1 = [1, 2]
nums2 = [3, 4]

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

这是问题,我刚开始刷leetCode还没多久,刚开始做这个题的时候,觉得真的挺难得。他的难点主要就是时间复杂度的问题。然后做了两三个小时实在做不出来我就找了看了官方给的解释,因为英语是个半吊子,理解起来蛮吃力的。查博客的话,大多只是写了个大概,对于我这个渣渣来说理解起来很吃力。所以我就想写一个更详细点的!

  做这个题的时候我们要注意题目的意思:题目所给的两个数组已经排好序了,如果没注意到这点,这个题是没办法做。然后开始分析:

(1)本题的难点是要有了复杂度,也就是log(n+m) 看见log我们所能想到的肯定是用到了分冶法,不然不会出现这个玩意的。

(2)然后开始理解中位数,就是能把一个数组分成两半。也就是 左边的最大的数 小于等于 右边最小的数

接下来就可以了:暂时不考虑极端情况,假设数组A和数组B长度都大于2;

A: A[0] A[1] A[2]..........A[m-3] A[m-2] A[m-1]

B: B[0] B[1] B[2]............B[n-3] B[n-2] B[n-1]

那么:分析一下, A和B的长度和起来是n+m,一般的长度就是 (n+m)/2

也就是 m/2 +n/2 那我们可以直接把 A和前半部分和B的前半部分 直接拿出来

A: A[0] A[1] A[2]...... A[j-1] | A[j] ....A[m-3] A[m-2] A[m-1] 将A分成了两半

B: B[0] B[1] B[2]....... B[i-1] | B[i].....B[n-3] B[n-2] B[n-1] 将B分成了两半

A[j]是A的中位数,B[i]是B的中位数,这个中位数很好求的,(j=m/2 i=n/2)



然后我们将 A的前半部分和B的前半部分 合在一起,把A的后半部分和B的后半部分合在一起, 假如点半部分合起来的最大值 小于等于后半部分的最小值,那么中位数不是直接就求出了了么。用一个关系式表示:

   j+i=(n+m)/2    && max(A[j-1] B[i-1]) <=  min(A[j] B[i])  

i和j是有关系的,这里不再讨论,看后面的关系式:要注意 A[j-1] 是一定小于 A[j]的(A和B是有序的)所以我们只需要让A[j-1] <=B[j] 就行,同理让 B[i-1] <= A[j] ,这样做的目的是什么呢?

  因为实际情况肯定和我们想的不一样:

情况1:

A[j-1] > B[i] 了怎么办? 这时候我们可以理解为,A的左边有数据过大,所以我们必须把这个大数给 右边,但是这样就会产生左边的总数少了,那我们就把B右边的给左边一个就行了:

A: A[0] A[1] A[2]...... A[j-2] | A[j-1] ....A[m-3] A[m-2] A[m-1] j-1 | j+1

B: B[0] B[1] B[2]....... B[i] | B[i+1].....B[n-3] B[n-2] B[n-1] i+1 | i-1

所以左边合起来的总是依旧等于右边合起来的总数:

同理:

B[i-1] > A[j] 就把 B[i-1]送给右边同时把A[i]送给左边就行。

A: A[0] A[1] A[2]...... A[J] | A[j+1] ....A[m-3] A[m-2] A[m-1] j+1 | j-1

B: B[0] B[1] B[2]....... B[i-2] | B[i-1].....B[n-3] B[n-2] B[n-1] i-1 | i+1

没有第三种情况:

不可能两个条件同时不符合:因为 A[j]>= A[j-1] 如果 A[j-1] > B[i] 那么 A[j] >= A[j-1] > B[i] >=B[i-1] 所以A[j]>B[i-1]

当然如果n活着m是奇数的话,也不需要在意,因为我们要的是 ( max(left_part)+min(right_part) )/2

 补充:我们是用 j来表示i的,所以m要小,为的是不让i算出了是个负数!!!

代码:



package day317;

public class leet_04 {
    public double  findMedianSortedArrays(int[] A,int B[]) {
    	int m=A.length;
    	int n=B.length;
    	if(m>n) {//保证m<n 意思就是B的长度大于等于A的长度
    		int[] temp=A;A=B; B=temp;
    		int tmp=m;m=n;n=tmp;
    	}
    	int iMin=0,iMax=m,halfLen=(n+m+1)/2;
    	while(iMin<=iMax) {
    		int i=(iMin+iMax)/2;
    		int j=halfLen-i;
    		if(i<iMax&&B[j-1]>A[i]) {
    			iMin=iMin+1;
    		}
    		else if(i>iMin&&A[i-1]>B[j]) {
    			iMax=iMax-1;
    		}
    		else {
    			int maxLeft=0;
    			if(i==0) {maxLeft=B[j-1];}
    			else if(j==0) {maxLeft=A[i-1];}
    			else {maxLeft=Math.max(A[i-1], B[j-1]);}
    			if((m+n)%2==1) {return maxLeft;}
    			int minRight=0;
    			if(i==m) {minRight=B[j];
    			}else if(j==n) {minRight=A[i];}
    			else {minRight=Math.min(B[j], A[i]);}
    			return (maxLeft+minRight)/2.0;
    		}
    	}
    	return 0.0;
    }
    public static void main(String[] args) {
    	int a[]={1,2,3};
    	int b[]= {2,3,4,5,6};
    	leet_04 l=new leet_04();
    	double c=l.findMedianSortedArrays(a,b);
    	System.out.println(c);
    }
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值