【问题标题】:Efficient algorithm to compute the median of pariwise absolute sums of a sorted array计算已排序数组的按位绝对和的中位数的高效算法
【发布时间】:2014-07-04 04:59:12
【问题描述】:

我正在尝试提出一种快速算法来计算 数量b[i]= med |y_i+y_j|, 1<=j!=i<=ny_1,...,y_n 已经排序(所以 b[] 是一个向量 与y[] 的长度相同)。 我将假设y[] 的所有元素都是唯一的 并且 n 是偶数。

所以,下面的代码计算 b[i] 的天真 (O(n**2)) 方式: (为方便起见,我用 R 写了这个,但我与语言无关)

n<-30
a_fast<-b_slow<-rep(NA,n)
y<-sort(rnorm(n,100,1))
z<-y
for(i in 1:n){
    b_slow[i]<-median(abs(y[-i]+y[i]))
}   

我在O(n) 有一个暂定的提议 -- 如下 -- 这样做。 但它仅在 y[] 包含正数时才有效。

我的问题是:我应该如何更改快速算法 当y[] 包含正面和 负数?这甚至可能吗?

编辑:

以及下面的代码(暂定)O(n) 方式 (为方便起见,我用 R 写了这个,但我与语言无关)

tryA<-floor(1+(n-1)/2+1)
tryB<-floor(1+(n-1)/2)
medA<-y[tryA]
medB<-y[tryB]
for(i in 1:(tryA-1)){
        a_fast[i]<-medA+y[i]
}
for(i in tryA:n){
        a_fast[i]<-medB+y[i]
}

简单示例:

简单的说明性示例。如果我们有一个长度为 4 的向量

-3, -1, 2, 4

那么,例如对于 i=1,3 个绝对成对和为

  4 1 1

它们的中位数是 1。

那么,例如对于 i=2,3 个绝对成对和为

  4 1 3

它们的中位数是 3。

这是一个更长的例子,有正面和负面y[]

 -1.27 -0.69 -0.56 -0.45 -0.23  0.07  0.13  0.46  1.56  1.72

这是我的新b_slow[](这是基本原理,用天真的方式计算):

1.20 0.92 1.00 1.01 0.79 0.53 0.56 0.53 1.33 1.49

但现在,我的新 a_fast[] 不再匹配:

 -1.20 -0.62 -0.49 -0.38 -0.16 -0.16 -0.10  0.23  1.33  1.49

编辑:

这是我对弗朗西斯解决方案的实现(直到我们有两个排序数组,其中位数很容易计算)。我在 R 中这样做是为了保持问题的精神。

尽管如此,我似乎缺少索引的校正因子(下面代码中的 ww),所以下面的代码有时会稍微偏离一点。这是因为在上面的定义中,我们计算了 n-1 个观测值 (i!=j) 的中位数。

 n<-100
 y<-rnorm(n)
 y<-sort(y)

 b<-rep(NA,n)
 #Naive --O(n**2)-- approch:
 for(i in 1:n){
     b[i]<-median(abs(y[-i]+y[i]))
 }

 k<-rep(NA,n)
 i<-1
 k[i]<-min(na.omit(c(which(y+y[i]>0)[1],n))) #binary search: O(log(n)) -- 
 for(i in 2:n){                  #O(n)
     k_prov<-k[i-1]
     while(y[k_prov]+y[i]>0 && k_prov>0)     k_prov<-k_prov-1
     k[i]<-max(k_prov+1,1)
     #for(i in 1:n){ should give the same result.
     #   k[i]<-which(y+y[i]>0)[1]
     #}
 }

 i<-sample(1:n,1)
 x1<--y[1:(k[i]-1)]-y[i]
 x2<-y[i]+y[n:k[i]]
 x3<-c(x1,x2)
 plot(x3)
 ww<-ifelse(i<k[i] & i>n/2,n/2+1,n/2)
 sort(x3)[ww]  #this can be computed efficiently: O(log(n))
 b[i]          #this is the O(n**2) result.

【问题讨论】:

  • 如果它们已经排序,中位数不应该是列表中间那些的总和吗?唯一的问题似乎是如果有奇数个元素该怎么办。
  • @user189035 如果元素个数为奇数,则排序数组的中位数为中间元素;否则是两个中间元素的平均值。如果数组已排序,您将在O(1) 中得到它。你不这样做有什么具体原因吗?还是我没发现问题?
  • 怀疑您的算法不适用于负数,因为您应该能够定义y'_i = y_i+y_1,计算y'_i 的中位数,然后从结果中减去y_1
  • @DietrichEpp:我想我不太明白你的评论。首先,我认为你应该做 y'_i=y_i-y_1 (使 y 为正)。接下来,我认为您应该添加 +2*y_1 来补偿(因为 y_1 在 y_i+y_j 中出现了两次)。最后,如果你尝试它不起作用(在计算快速版本之前转换 y,然后转换回来不会给出与在未转换的 y 上计算的慢速版本相同的数字)–
  • 好吧,我没看到里面的绝对值。我将其添加到问题的标题中。

标签: c++ c algorithm language-agnostic


【解决方案1】:

这是一个 O(Nxln(N)xln(N)) 的解决方案:

对于所有我:

1) 找到项目 k 如j&lt;k &lt;=&gt; y[j]+y[i]&lt;0 (dichotomy, O(ln(N)))

k 分隔两个排序列表:一个在 -y[i] 之上,另一个在 -y[i] 之下,其符号应更改为 abs(y[i]+y[j])。 现在,我们正在寻找这些列表的中位数。

从这里开始,就是finding the median of two sorted lists的问题,重复了n次。

2)让我们选择这些列表的最大值 (M=abs(y[1]-y[i]) 或 M=abs(y[size]-y[i])) 和最小值 (m around k)并重新开始二分法(O(ln(N))。让我们从选择中间(M + m)/ 2开始......在任何阶段,让我们选择中间......

3)这个大二分法的阶段:第一个列表中有多少项 y[j]+y[i] 在 (M+m)/2 之上?再次二分法...... O(ln(N))。第二个列表中有多少项 -y[j]-y[i] 在 (M+m)/2 以上?你猜怎么了 ?二分法...将这两个数字相加。如果在(size-1)/2以上,m=(M+m)/2。否则 M=(M+m)/2。

4)如果 m=M 停止! b[i]=m;

我猜有人会提出更好的解决方案...

编辑:我应该感谢 @user189035 链接到 O(ln(n+m)) 算法来计算两个排序列表的中位数。 How to find the kth smallest element in the union of two sorted arrays?

再见,

【讨论】:

    猜你喜欢
    • 2021-11-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-22
    相关资源
    最近更新 更多