我尝试打高尔夫球。
finding the minimum value of ∑W_i*|X-X_i|
的问题减少为找到权重为x[i]
的{{1}}列表的加权中位数(请参阅下面的定义)。你将如何用最短,最简单和最美丽的程序来做到这一点?
以下是我的代码最初的显示方式(解释位于the answer to the question,短版本作为以下答案之一发布)。
w[i]
(实际上,当您看到变量 #define zero(x) ( abs(x) < 1e-10 ) /* because == doesn't work for floats */
float sum = 0;
int i;
for (i = 0; i < n; i++)
sum += w[i];
while (sum > 0)
sum -= 2*w[--i];
right = x[i] // the rightmost minimum point
left = ( zero(sum) && zero(w[i]-w[i-1]) ) ? x[i-1] : right;
answer = (left + right) / 2;
和i
重复使用时,它已经过大量优化)
浮点数和整数:不同的语言有不同的浮点算术标准,所以我重新设计问题,让sum
和x[i]
为整数如果您愿意,可以返回答案值的两倍(总是整数)。您可以返回,打印或将答案分配给变量。
加权中位数和澄清的定义:
w[i]
的已排序数组x[i]
的中位数为n
或x[n/2]
,具体取决于(x[n/2-1/2]+x[n/2+1/2])/2
是奇数还是偶数n
的{{1}}的加权中位数定义为较大数组的中位数,其中x[i]
的每次出现都已更改为w[i]
x[i]
次出现w[i]
1}}。要求的一个原因是我假设最合适的语言将使用lambdas进行简单的数组求和和迭代。我认为功能语言可能是合理的,但我不确定 - 所以这是问题的一部分。我希望看到像
这样的东西x[i]
Dunno,如果有任何语言,这是可能的,实际上更短。
// standard function add := (a,b) :-> a + b
myreduce := w.reduce
with: add
until: (value) :-> 2*value >= (w.reduce with:add)
answer = x [myreduce from:Begin] + x [myreduce from:End]
答案:6或12。
static int n = 10;
for (int j = 0; j < n; j++) {
w[j] = j + 1;
x[j] = j;
}
答案:6.5或13。
答案 0 :(得分:5)
继续直接在解释器中输入。提示符是三个空格,因此缩进行是用户输入。
m=:-:@+/@(((2*+/\)I.+/)"1@(,:(\:i.@#))@[{"0 1(,:(\:i.@#))@])
我在其他答案中使用的测试数据:
1 1 1 1 m 1 2 3 4
2.5
1 1 2 1 m 1 2 3 4
3
1 2 2 5 m 1 2 3 4
3.5
1 2 2 6 m 1 2 3 4
4
测试数据添加到问题中:
(>:,:[)i.10
1 2 3 4 5 6 7 8 9 10
0 1 2 3 4 5 6 7 8 9
(>:m[)i.10
6
(([+<&6),:>:)i.9
1 2 3 4 5 6 6 7 8
1 2 3 4 5 6 7 8 9
(([+<&6)m>:)i.9
6.5
i =: (2 * +/\) I. +/
第一个指数使得总和大于或等于累计总和的两倍。
j =: ,: (\: i.@#)
列表及其反向。
k =: i"1 @ j @ [
第一个指数,如 - 见上面 - 左参数及其反转。
l =: k {"(0 1) j @ ]
分别从右参数及其反向提取的索引。
m =: -: @ +/ @ l
结果列表总和的一半。
答案 1 :(得分:3)
所以,这就是我如何挤压自己的解决方案:仍然留下一些空白:
int s = 0, i = 0;
for (; i < n; s += w[i++]) ;
while ( (s -= 2*w[--i] ) > 0) ;
a = x[i] + x[ !s && (w[i]==w[i-1]) ? i-1 : i ];
答案 2 :(得分:2)
Haskell代码,ungolfed:尝试合理的功能解决方案。
import Data.List (zip4)
import Data.Maybe (listToMaybe)
mid :: (Num a, Ord a) => [a] -> (Int, Bool)
mid w = (i, total == part && maybe False (l ==) r) where
(i, l, r, part):_ = dropWhile less . zip4 [0..] w v $ map (2*) sums
_:sums = scanl (+) 0 w; total = last sums; less (_,_,_,x) = x < total
v = map Just w ++ repeat Nothing
wmedian :: (Num a, Ord a) => [a] -> [a] -> (a, Maybe a)
wmedian w x = (left, if rem then listToMaybe rest else Nothing) where
(i, rem) = mid w; left:rest = drop i x
> wmedian [1,1,1,1] [1,2,3,4] (2,Just 3) > wmedian [1,1,2,1] [1,2,3,4] (3,Nothing) > wmedian [1,2,2,5] [1,2,3,4] (3,Just 4) > wmedian [1,2,2,6] [1,2,3,4] (4,Nothing)
> wmedian [1..10] [0..9] (6,Nothing) > wmedian ([1..6]++[6..8]) [1..9] (6,Just 7)
我原来的J解决方案是对上述Haskell代码的直接翻译。
这是当前J代码的Haskell转换:
{-# LANGUAGE ParallelListComp #-}
import Data.List (find); import Data.Maybe (fromJust)
w&x=foldr((+).fst.fromJust.find((>=sum w).snd))0[f.g(+)0$map
(2*)w|f<-[zip x.tail,reverse.zip x]|g<-[scanl,scanr]]/2
是的...请不要写这样的代码。
> [1,1,1,1]&[1,2,3,4] 2.5 > [1,1,2,1]&[1,2,3,4] 3 > [1,2,2,5]&[1,2,3,4] 3.5 > [1,2,2,6]&[1,2,3,4] 4 > [1..10]&[0..9] 6 > ([1..6]++[6..8])&[1..9] 6.5
答案 3 :(得分:2)
简短,做你期望的。不是特别节省空间。
def f(l,i):
x,y=[],sum(i)
map(x.extend,([m]*n for m,n in zip(l,i)))
return (x[y/2]+x[(y-1)/2])/2.
这是使用itertools的恒定空间版本。它仍然必须迭代sum(i)/ 2次,因此它不会超过索引计算算法。
from itertools import *
def f(l,i):
y=sum(i)-1
return sum(islice(
chain(*([m]*n for m,n in zip(l,i))),
y/2,
(y+1)/2+1
))/(y%2+1.)
答案 4 :(得分:1)
的Python:
a=sum([[X]*W for X,W in zip(x,w)],[]);l=len(a);a[l/2]+a[(l-1)/2]
答案 5 :(得分:0)
这样的东西? O(n)运行时间。
for(int i = 0; i < x.length; i++)
{
sum += x[i] * w[i];
sums.push(sum);
}
median = sum/2;
for(int i = 0; i < array.length - 1; i++)
{
if(median > sums[element] and median < sums[element+1]
return x[i];
if(median == sums[element])
return (x[i] + x[i+1])/2
}
不确定如何获得中位数的两个答案,是指sum / 2是否恰好等于边界?
编辑:看了你的格式化代码后,我的代码基本上做了同样的事情,你想要一个更高效的方法吗?EDIT2:搜索部分可以使用修改后的二进制搜索来完成,这会使它稍快一些。
index = sums.length /2;
finalIndex = binarySearch(index);
int binarySearch(i)
{
if(median > sums[i+1])
{
i += i/2
return binarySearch(i);
}
else if(median < sums[i])
{
i -= i/2
return binarySearch(i);
}
return i;
}
必须做一些检查以确保它不会在边缘情况下无限地继续。
答案 6 :(得分:-5)
只是对你的代码的评论:我真的希望我不必维护它,除非你还写了这里所需的所有单元测试: - )
这与你的问题无关,但通常,“最短的编码方式”也是“最难维护的方式”。对于科学应用,它可能不是一个显示塞子。但对于IT应用程序来说,它是。
我认为必须说。一切顺利。