LeetCode刷题笔录 Median Of Two Sorted Arrays

50 篇文章 0 订阅
26 篇文章 0 订阅
  1. 先说临界情况

  2. A为空或者B为空
    直接在非空数组中找第k大的数即可。O(1)
  3. 找最小的数,k==0的情况,也简单,比较两个数组最开头的元素,谁小就是谁
  1. 然后就是比较复杂的情况,假设寻找目标target是下标为k的数。
    那么意味着在排好的数组中,在目标数之前,一共有k个比目标更小的数。
    将k分成两份,一份在A的前端,一份在B的前端。这里其实将k怎么分配是一个可以讨论的问题,但是平分k可以得到平均最快的效果。
    设k = ka + kb,(k是偶数简单,k是奇数的话,剩下那一个随便放在两个数组中哪一个中都可以)

    这里可以列出来我们想要的效果:
    k=1 —-> ka = 1, kb = 1
    k=2 —-> ka = 1, kb = 1
    k=3 —-> ka = 1, kb = 1. [+1,表示还有一个元素,可以随意分配在ka或者kb中,只要不越界]
    k=4 —-> ka = 2, kb = 2
    k=5 —-> ka = 2, kb = 2. [+1]
    已经可以看出来规律了,这个造成了下面代码中比较复杂的部分,这些细节消耗的时间不少啊。

    然后就是主要逻辑

  2. 如果A[ka-1] >= B[kb-1]
    说明在B前端的kb个数中,不可能出现我们要寻找的目标。
    为什么呢?
    假如A一共有m个数,B一共有n个数。
    那么target(下标是k)后面有且只有n + m – 1 – k个数;
    但是B[kb-1]在B中已经排在n – kb个数之前,加上A中的m – ka + 1(A[ka-a]),也就是说在排序后的整体数组中排在B[kb-1]之后的数,至少有n – kb + m – ka + 1 = n + m – k + 1个。
    由于n + m – k + 1 > n + m – k – 1,所以B前端kb个数都不可能是target。
    所以此时可以将问题转化为,在A[0,...,m-1]和B[kb,...,n-1]中,寻找下标为k – kb的数。
  3. 否则,A[ka-1] < B[kb-1]
    同上,可以剔除A前端的ka个数。

这样循环下去,就能以二分的速度找到目标。

这个问题不仅要找到第k大的数,当C是偶数的时候,还要找到第k+1个数,取两者均值。

public class MedianOfTwoSortedArrays {
	public double findMedianSortedArrays(int A[], int B[], int m, int n) {
        // Start typing your Java solution below
        // DO NOT write main() function
        
		int lowA =0;
		int lowB = 0;
		int highA = m - 1;
		int highB = n - 1;
		int k = (m + n) / 2;
		if((m + n) % 2 == 0){
			return (findKth(A, B, lowA, highA, lowB, highB, k) + findKth(A, B, lowA, highA, lowB, highB, k + 1)) / 2.0;
		}
		else
			return findKth(A, B, lowA, highA, lowB, highB, k);
    }
	
	public int findKth(int A[], int B[], int lowA, int highA, int lowB, int highB, int k){
		int m = highA - lowA + 1;
		int n = highB - lowB + 1;
		if (m == 0) 
			return B[lowB + k];
		if (n == 0)
			return A[lowA + k];
		if (k == 0 )
			return A[lowA] > B[lowB] ? B[lowB] : A[lowA];
		
		/*
		int midA = (lowA + highA) / 2;
		int midB = (lowB + highB) / 2;
		if(A[midA] > B[midB]){
			if((midA + midB + 1) >= k)
				return findKth(A, B, lowA, midA, lowB, highB, k);
			else
				return findKth(A, B, lowA, highA, midB + 1, highB, k - (n / 2 + 1));
		}
		else{
			if((midA + midB + 1) >= k)
				return findKth(A, B, lowA, highA, lowB, midB, k);
			else
				return findKth(A, B, midA + 1, highA, lowB, highB, k - (m / 2 + 1));
		}
		*/
			// Reduce search ranges in A and B
		int midA = m * k / (m + n);
		int midB = k - midA - 1;
		 // Add offset so that imid_A and imid_B index directly into A and B,  respectively 
		midA += lowA;
		midB += lowB;
		if (A[midA] > B[midB]) {
			k -= midB - lowB + 1;
			highA = midA;
			lowB = midB + 1;
		}
		else {
			k -= midA - lowA + 1;
			lowA = midA + 1;
			highB = midB;
		}
		return findKth(A, B, lowA, highA, lowB, highB, k);
	}
	
	
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值