【发布时间】:2014-07-04 04:59:12
【问题描述】:
我正在尝试提出一种快速算法来计算
数量b[i]= med |y_i+y_j|, 1<=j!=i<=n时
y_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