查找最近距离的总和


10

对于此任务,您的代码应采用整数X和Y的两个排序数组作为输入。它应该计算X中每个整数与其Y中最接近的数字之间的绝对距离之和。

例子:

X = (1 5,9)
Y = (3,4,7)

距离是2 +1 + 2。

X = (1,2,3)
Y = (0,8)

距离是1 + 2 + 3。

您的代码可以采用任何方便的方式进行输入。

主要限制是您的代码必须在两个数组的总和中以线性时间运行。。(您可以假设将两个整数相加需要固定的时间。)


我们可以使用列表或流而不是数组吗?
Ad Hoc Garf Hunter '18

@CatWizard是的,您可以!
Anush

1
如何1 + 2 + 3源自X = (1,2,3)Y = (0,8)
guest271314 '18

1
@ guest271314最接近的数量每两个123YIS 0。因此,差异是1-02-03-0
dylnan '18

1
@FreezePhoenix,因为两个列表都已排序,所以可以在O(n + m)中进行操作,因为您可以遍历列表,访问每个元素一次,并且只要跟踪最靠近X i的元素Y j,就可以检查Y jY j + 1,因为其中一个最接近X i + 1XÿĴX一世ÿĴÿĴ+1个X一世+1个
朱塞佩

Answers:


6

Haskell70 64字节

a%b=abs$a-b
x@(a:b)#y@(c:d)|e:_<-d,a%c>a%e=x#d|1>0=a%c+b#y
_#_=0

在线尝试!

说明

首先,我们定义(%)为两个数字之间的绝对差。然后我们定义(#)为有趣的函数。在第一行中,当两个列表都不为空时,我们进行匹配:

x@(a:b)#(c:d:e)

在我们从这里第一种情况下,我们绑定de:_e:_<-d。这样可以确保d非空值并将其第一个元素设置为e

然后,如果()的第二个元素比X()的第一个元素更靠近第一个(),我们返回删除Y的第一个元素,然后再次使用相同的X进行调用。ÿecXax#dÿX

如果我们匹配模式但不通过条件,则执行:

a%c+b#y

这将删除的第一项,并将其与X的第一元素的绝对差加到剩余结果中。XX

最后,如果我们不匹配模式,则返回。不匹配模式意味着X必须为空,因为Y不能为空。0Xÿ

该算法的顺序符号为Ø|X|+|ÿ|

Haskell,34个字节

这是我在时间中的处理方式:Ø|X|×|ÿ|

x#y=sum[minimum$abs.(z-)<$>y|z<-x]

在线尝试!


我在问题中阐明,我们可以假设将两个整数相加需要固定的时间。
Anush

2

Python 2中124 120个字节

X,Y=input()
i=j=s=0
while i<len(X):
 v=abs(Y[j]-X[i])
 if j+1<len(Y)and v>=abs(Y[j+1]-X[i]):j+=1
 else:s+=v;i+=1
print s

在线尝试!

通过移至程序对函数,节省了4个字节。

满足时间复杂性约束是可能的,因为两个列表都已排序。请注意,每次循环,都会i递增或j递增。因此,循环大多数情况下执行len(X)+len(Y)


我在问题中阐明,我们可以假设将两个整数相加需要固定的时间。
Anush

1

C(gcc),82个字节

n;f(x,y,a,b)int*x,*y;{for(n=0;a;)--b&&*x*2-*y>y[1]?++y:(++b,--a,n+=abs(*x++-*y));}

这将输入作为两个整数数组及其长度(因为C无法以其他方式获取其长度)。可以证明这是O(a+b)因为循环中的ab在循环的每个迭代中递减而导致的,它在a到达时终止0(并且b不能在以下递减0)。

在线尝试!

n;                     // define sum as an integer
f(x,y,a,b)             // function taking two arrays and two lengths
int*x,*y;              // use k&r style definitions to shorten function declaration
{
 for(n=0;              // initialize sum to 0
 a;)                   // keep looping until x (the first array) runs out
                       // we'll decrement a/b every time we increment x/y respectively
 --b&&                 // if y has ≥1 elements left (b>1, but decrements in-place)...
 *x*2-*y>y[1]?         // ... and x - y > [next y] - x, but rearranged for brevity...
 ++y:                  // increment y (we already decremented b earlier);
 (++b,                 // otherwise, undo the in-place decrement of b from before...
 --a,n+=abs(*x++-*y))  // decrement a instead, add |x-y| to n, and then increment x
;}

一些注意事项:

  • 不用索引数组,而是增加指针并直接取消引用可以节省足够的字节数,以使其值得使用(*xvs x[a]y[1]vs y[b+1])。

  • --b&&条件检查b>1以一种迂回的方式-如果b1,它会评估为零。由于此操作已修改b,因此我们无需在三进制的第一个分支中更改它(前进y),但确实需要在第二个分支中更改它(前进x)。

  • 不需要return声明,因为黑魔法。(我认为这是因为最后一个要求值的语句将始终是n+=...表达式,它使用与用于返回值的寄存器相同的寄存器。)


0

Ruby,88个字节

->(p,q){a=q.each_cons(2).map{|a|a.sum/a.size}
x=a[0]
p.sum{|n|x=a.pop if n>x
(n-x).abs}}

在线尝试!

同样,为了娱乐,一个较短的匿名函数不能完全满足复杂性限制:

->(a,b){a.map{|x|x-b.min_by{|y|(x-y).abs}}.sum}

您能简单地解释一下此代码如何工作吗?我不知道它是否在线性时间内运行。
Anush

2
这将使问题中的第一个测试用例以及的输入都失败[5, 6], [0, 1, 5]
门把手

0

JavaScript(Node.js),80字节

x=>g=(y,i=0,j=0,v=x[i],d=v-y[j],t=d>y[j+1]-v)=>1/v?g(y,i+!t,j+t)+!t*(d>0?d:-d):0
  • 它以O(| X | + | Y |)运行:每个递归都以O(1)运行,并且递归| X | + | Y | 次。
    • xy是通过引用传递的,不会复制内容
  • 1/v如果x[i]超出范围则为假,否则为真
  • t-> d>y[j+1]-v-> v+v>y[j]+y[j+1]为假,只要满足以下条件。和手段y[j]是最接近数vy
    • v小于(y[j]+y[j+1])/2,或
    • y[j+1]超出范围,它将转换为NaN,并与NaNyield 进行比较false
      • 这就是为什么我们不能翻转 >符号以节省1个字节
  • t 始终是布尔值,并且 *在计算之前将其转换为0/1

在线尝试!


0

Mathematica,40个字节

x = {1, 5, 9};
y = {3, 4, 7};

Norm[Flatten[Nearest[y] /@ x] - x]

如果必须使用输入来创建完整程序,请执行以下操作:

f[x_,y_]:= Norm[Flatten[Nearest[y] /@ x] - x]

以下是获取1,000,000点(每10,000个样本)的时间y

在此处输入图片说明

接近线性。


1
该答案是一个代码段,因为您的输入被视为预先存在的变量。您应将其重新格式化为子程序或完整程序。
Ad Hoc Garf Hunter

我也对此工作在线性时间内有点怀疑,您对为什么要这样做有任何道理吗?Mathematica在其内置函数的复杂性方面往往不太透明。
Ad Hoc Garf Hunter
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.