java 数组中位数_找到数组总和的中位数

正确的O(n)解决方案非常复杂,需要大量的文本,代码和技巧来解释和证明 . 更确切地说,令人信服地需要3页,这里可以详细查看http://www.cse.yorku.ca/~andy/pubs/X+Y.pdf(在评论中找到 simonzack ) .

它基本上是一个聪明的分而治之算法,除其他外,它利用了这样一个事实:在一个排序的n乘n矩阵中,人们可以在 O(n) 找到小于/大于给定的元素数量号码 k . 它递归地将矩阵分解为较小的子矩阵(通过仅取奇数行和列,产生具有 n/2 列和 n/2 行的子矩阵),结合上述步骤,导致复杂度为 O(n) + O(n/2) + O(n/4)... = O(2*n) = O(n) . 太疯狂了!

我无法解释它比论文更好, which is why I'll explain a simpler, O(n logn) solution instead :) .

O(n * logn)解决方案:

It's an interview! 你无法及时得到那个 O(n) 解决方案 . 嘿,为什么不提供一个解决方案,虽然不是最优的,但表明你可以做得比其他明显的候选人更好?

我将利用上面提到的 O(n) 算法来查找在排序的 n-by-n 矩阵中小于/大于给定数字 k 的数字量 . 请记住,我们不需要实际的矩阵!由OP描述的两个大小为 n 的数组的笛卡尔和,得到一个排序的 n-by-n 矩阵,我们可以通过考虑数组的元素来模拟如下:

a[3] = {1, 5, 9};

b[3] = {4, 6, 8};

//a + b:

{1+4, 1+6, 1+8,

5+4, 5+6, 5+8,

9+4, 9+6, 9+8}

因此,每行包含非递减数字,每列也包含非递减数字 . 现在,假装给你一个号码 k . 我们想在 O(n) 找到这个矩阵中有多少数字小于 k ,有多少数字更大 . 显然,如果两个值都小于 (n²+1)/2 ,那意味着 k 是我们的中位数!

算法非常简单:

int smaller_than_k(int k){

int x = 0, j = n-1;

for(int i = 0; i < n; ++i){

while(j >= 0 && k <= a[i]+b[j]){

--j;

}

x += j+1;

}

return x;

}

这基本上计算了每行符合条件的元素数量 . 由于行和列已按上面所示排序,因此这将提供正确的结果 . 由于 i 和 j 每次最多迭代 n 次,算法为 O(n) [注意 j 不会在 for 循环内重置] . greater_than_k 算法类似 .

现在,我们如何选择 k ?那是 logn 部分 . Binary Search! 正如其他答案/评论中所提到的,中位数必须是此数组中包含的值:

candidates[n] = {a[0]+b[n-1], a[1]+b[n-2],... a[n-1]+b[0]}; .

只需对此数组[也 O(n*logn) ]进行排序,然后对其运行二进制搜索 . 由于数组现在处于非递减顺序,因此可以直截了当地注意到小于每个 candidate[i] 的数字量也是非递减值(单调函数),这使得它适合于二进制搜索 . 其结果 smaller_than_k(k) 返回小于 (n²+1)/2 的最大数 k = candidate[i] 是答案,并且在 log(n) 迭代中获得:

int b_search(){

int lo = 0, hi = n, mid, n2 = (n²+1)/2;

while(hi-lo > 1){

mid = (hi+lo)/2;

if(smaller_than_k(candidate[mid]) < n2)

lo = mid;

else

hi = mid;

}

return candidate[lo]; // the median

}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值