找到两个有序数组的中位数

题目要求时间复杂度为log(m+n)。

可以将此题转换成寻找第k小的数的问题!

算法的原理:

假设要找第k小的数,我们要比较A[k/2-1]B[k-k/2-1]这两个元素,这两个元素分别表示A的第k/2小的元素和B的第k-k/2小的元素。至于为什么要去这两个数,是因为k/2+(k-k/2)等于k,所以去这两个数比较。

这两个元素比较共有三种情况:><=

如果A[k/2-1]<B[k/2-1],这表示A[0]A[k/2-1]的元素都在AB合并之后的前k小的元素中,直接抛弃即可。

如果A[k/2-1]>B[k/2-1]时存在类似的结论。

如果A[k/2-1]=B[k/2-1]时,我们已经找到了第k小的数,也即这个相等的元素

通过上面的分析,我们即可以采用递归的方式实现寻找第k小的数。此外我们还需要考虑几个边界条件:

如果A或者B为空,则直接返回B[k-1]或者A[k-1]

如果k1,我们只需要返回A[0]B[0]中的较小值;

完整代码:

public static double findMedianSortedArrays(int A[], int m, int B[], int n) {
		int total = m + n;
		if ((total & 0x1) != 0)
			return findKth(A, m, B, n, total / 2 + 1, 0, 0);
		else
			return (findKth(A, m, B, n, total / 2, 0, 0) + findKth(A, m, B, n,total / 2 + 1, 0, 0)) / 2;
	}
	public static double findKth(int a[], int m, int b[], int n, int k, int head_a, int head_b) {
		if (m > n)
			return findKth(b, n, a, m, k, head_b, head_a);
		if (m == 0)
			return b[k - 1+head_b];
		if (k == 1)
			return Math.min(a[head_a], b[head_b]);
		int pa = Math.min(k / 2, m), pb = k - pa;
		int new_pa = head_a+(pa-1),new_pb = head_b+(pb-1);
		if (a[new_pa] < b[new_pb])
			return findKth(a, m - pa, b, n, k - pa, head_a += pa, head_b);
		else if (a[new_pa] > b[new_pb])
			return findKth(a, m, b, n - pb, k - pb, head_a, head_b += pb);
		else
			return a[new_pa];
	}

代码解释:

head_ahead_b:表示抛弃无用元素后,数组下一次开始的位置

papb:计算理论上要比较的两个元素的位置

new_panew_pb:因为抛弃元素后,数组的起始位置往后移了,所以需要重新计算要比较的两个元素的实际所在位置

④在递归调用findKth()方法时,参数的解释:m-pa表示抛弃元素后数组a剩余元素的长度;k-pa表示因为抛弃了pa个元素,所以不能再寻找第k小的数了要变成寻找第k-pa小的数;抛弃pa个元素后,数组a的起始是从head_a += pa开始


在最好情况下,每次都有k一半的元素被删除,所以算法复杂度为logk,由于求中位数时k为(m+n/2,所以算法复杂度为log(m+n)


连接:

http://blog.csdn.net/yutianzuijin/article/details/11499917

http://blog.csdn.net/fightforyourdream/article/details/17351395 


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值