变相的排列


17

给定一个n维向量v与真正的条目,找到最接近的置换p(1,2,...,n)相对于所述l1 -distance。

细节

  • 如果是更方便,你可以使用置换(0,1,...,n1)代替。如果存在多个最接近的排列,则可以输出任何一个或全部替换。
  • 两个向量u v之间的l1距离定义为d u v = i | u iv i | u,v
    d(u,v)=i|uivi|.
  • 如果需要,可以假定输入仅由整数组成。

例子

[0.5  1] -> [1 2], [2 1]
c*[1 1 ... 1] -> any permutation
[1 4 2 6 2] -> [1 4 3 5 2], [1 4 2 5 3]
[1 3 5 4 1] -> [2 3 5 4 1], [1 3 5 4 2]
[7 7 3 2 5 6 4 2] -> [8 7 3 2 5 6 4 1], [8 7 3 1 5 6 4 2], [7 8 3 2 5 6 4 1], [7 8 3 1 5 6 4 2]
[-2 4 5 7 -1 9 3] -> [1 4 5 6 2 7 3], [2 4 5 6 1 7 3], [1 4 5 7 2 6 3], [2 4 5 7 1 6 3]
[0 4 2 10 -1 10 5] -> [1 4 2 6 3 7 5], [1 4 3 6 2 7 5], [2 4 3 6 1 7 5], [3 4 2 6 1 7 5], [1 4 2 7 3 6 5], [1 4 3 7 2 6 5], [2 4 3 7 1 6 5], [3 4 2 7 1 6 5]

八度脚本用于生成更多示例。


我们是否保证的所有元素v都大于0?或者,至少不是0
毛茸茸的

1
不可以,的条目v可以是任何整数。(添加了更多示例。)
瑕疵的

如果它们可以是任何实数,则[1.6 2]是一个重要的测试用例(贪婪算法/词典编排给出错误的答案)。
histocrat

2
伪装重复?我不确定它是否应该这样关闭,因为它不是同一任务(如xnor现在所证明的)并不明显。
Arnauld

1
(实际上,这不是同一任务,但是链接式挑战的所有解决方案都是该挑战的解决方案。)
Arnauld

Answers:


13

Python 2,60个字节

def f(l):z=zip(l,range(len(l)));print map(sorted(z).index,z)

在线尝试!

使用零索引。

具有简单思想的快速算法。如果我们不是需要置换的输入列表,使之尽可能接近(1,2,...,n)有可能,我们就应该排序,如下证明。因为我们不是置换(1,2,...,n),我们选择置换该公司订购的相同的方式输入列表,就像在我的挑战模仿排序(除输入可能有重复)。(编辑:Miles指出了这个更加相同的挑战,Dennis的回答与此相同。)

声明:列表的排列l,其距离最小化(1,2,...,n)l排序。

证明:考虑一些其他置换ll。我们将证明它不能比l排序更好。

挑两个指数i,jl具有外的顺序,即,其中i<jli>lj。我们发现,他们交换不能增加的距离(1,2,...,n)。我们注意到,互换改变这两个要素的贡献如下:

|lii|+|ljj||lij|+|lji|.

这是显示这不能增加的一种好方法。考虑两个人走在数轴上,一个从去lii和其他来自ljj。他们行走的总距离是左侧的表达式。由于i<jli>lj,他们切换谁在数行,这意味着它们必须在他们的散步在某些点交叉更高,称之为p。但是当他们达到p,然后他们可以交换目的地并步行相同的总距离。然后,对于他们来说,从一开始就走到他们交换的目的地,而不是使用p作为航路点,这总会在右侧,这并不坏。

所以,在分选两个异序元素l使得其距离(1,2,...,n)更小或相同。重复此过程将最终对l排序。因此,l分拣至少不如l对于任何选择l,这意味着它是最佳的或并列最佳。

需要注意的是唯一的财产(1,2,...,n),我们使用的是它的排序,所以相同的算法将努力置换任何给定的名单的距离尽量减少任何固定列表。

在代码中,的唯一目的z=zip(l,range(len(l)))是使输入元素与众不同,即避免联系,同时在不相等元素之间保持相同的比较。如果我们保证输入没有重复,我们可以删除它而只lambda l:map(sorted(l).index,l)


出色的洞察力
乔纳(Jonah)

您已将其简化为查找顺序
英里

@miles这很有趣,即使我写下了答案,我也完全忘记了这个挑战,而Dennis给出了我帮助打高尔夫球的确切Python答案
xnor19

那“视觉证明”是整洁的。我有相同的想法,但必须列出该公式的每种情况以证明这一点。作为一个方面的话,在使用Python第三方库获得行列的几个选择显示在这个岗位
乔尔(Joel)

5

05AB1E,7个字节

āœΣαO}н

在线尝试!


说明

ā              # get the numbers 1 to len(input) + 1
 œ             # Permutations of this
  Σ  }         # Sort by ...
   α           # Absolute difference
    O          # Sum these
      н        # And get the first one 
               # implicitly print

1
每当我对此感到惊讶时,05AB1E 不能做什么?
随机家伙

5
@Therandomguy在05AB1E中并没有很多事情无法完成,但是它的缺点是:基于正则表达式的挑战;基于矩阵的挑战(尽管在一些新的内置功能之后已得到改善);缺乏虚数;与日期/时间相关的挑战;等等,尽管很难,但是通常还是可以做到的。举两个例子:工作日倒计时(手动进行到第二天和获取星期几);Quine以二进制形式输出自身(UTF-8转换是手动完成的)。
凯文·克鲁伊森

@Grimy现在应该修复:)
过期的数据

3

Perl 6,44个字节

{permutations(+$_).min((*[]Z-$_)>>.abs.sum)}

在线尝试!

返回索引为0的第一个最小排列的匿名代码块。

说明:

{                                          }   # Anonymous code block
 permutations(+$_)                             # From the permutations with the same length
                  .min(                   )    # Find the minimum by
                                      .sum       # The sum of
                                >>.abs           # The absolute values of
                       (*[]Z-$_)                 # The zip subtraction with the input

我想我也许也可以摆脱.sum绝对值列表的排序,但我不确定这确实是正确的,尽管它可以通过当前的测试用例。


1
那也伤了我的脑筋(或者最常见的问题是“贪婪算法是否可以解决这个问题?”)。最简单的反例是[0.6 1](假设我们的索引为0),如果您针对第一个值进行优化,则得到[1,0]1.4分,但是如果针对整个矢量进行优化,则在第二个位置获得更有价值的得分的0.6。
histocrat


2

果冻,5 个字节

Œ¿œ?J

单子链接接受一个数字列表,该列表产生一个整数列表。

在线尝试!或查看测试套件

怎么样?

Œ¿œ?J - Link: list of numbers, X
Œ¿    - Index of X in a lexicographically sorted list of
         all permutations of X's items
    J - range of length of X
  œ?  - Permutation at the index given on the left of the
         items given on the right

NB L(的长度)将代替,J因为œ?给定一个整数n,在右边将隐式地使该范围[1..n]适用,但是J明确的。


2

红宝石63 60字节

->v{[*1..v.size].permutation.max_by{|p|eval [p,0]*'*%p+'%v}}

在线尝试!

这里有一个数学技巧也可能对其他答案有帮助-我们不是使差异的绝对值之和最小化,而是使乘积之和最大化。为什么行得通?

最小化 (x-y) squared不等于最小化的总和|x-y|,但是它总是会给出一个有效的答案,它只是优先考虑减小大差异而不是小差异,而实际的挑战在两者之间并不重要。

但是(x-y)*(x-y)= x*x+y*y-2*x*y。由于平方项对于任何排列总会出现在总和中的某个位置,因此它们不会影响结果,因此我们可以简化为-2*x*y。的2因素了,所以我们可以简化为-x*y。然后,如果我们将最小化更改为最大化,则可以简化为x*y

从直觉上讲,这类似于观察到如果您尝试使用一组水平墙和一组垂直墙来最大化平方英尺,则最好不要将大小彼此接近的墙配对以创建尽可能靠近正方形。 3*3 + 4*4 = 25,而3*4 + 4*3 = 24

编辑:通过生成和评估格式字符串而不是使用zip和sum,节省了三个字节。


2
最小化(xy)平方和并不等同于最小化| xy |,但是它将始终给出有效的答案。为什么会这样呢?有没有ÿ 最小化 |X-ÿ| 但不是 X-ÿ2
乔尔(Joel)

1

盖亚(Gaia),13个字节

e:l┅f⟪D†Σ⟫∫ₔ(

在线尝试!

e:		| eval and dup input
l┅f		| push permutations of [1..length(input)]
⟪   ⟫∫ₔ		| iterate over the permutations, sorting with minimum first
 D†Σ		| the sum of the absolute difference of the paired elements
       (	| and select the first (minimum)

1

JavaScript(ES6),61个字节

基于xnor的见解

a=>[...a].map(g=n=>g[n]=a.sort((a,b)=>a-b).indexOf(n,g[n])+1)

在线尝试!

已评论

a =>                    // a[] = input array
  [...a]                // create a copy of a[] (unsorted)
  .map(g = n =>         // let g be in a object; for each value n in the copy of a[]:
    g[n] =              //   update g[n]:
      a.sort(           //     sort a[] ...
        (a, b) => a - b //       ... in ascending order
      ).indexOf(        //     and find the position
        n,              //       of n in this sorted array,
        g[n]            //       starting at g[n] (interpreted as 0 if undefined)
      ) + 1             //     add 1
  )                     // end of map()

JavaScript(ES6), 130  128字节

还有 一定要  绝对是一个更直接的方式...

0索引。

a=>(m=g=(k,p=[])=>1/a[k]?(h=i=>i>k||g(k+1,b=[...p],b.splice(i,0,k),h(-~i)))``:p.map((v,i)=>k+=(v-=a[i])*v)|k>m||(R=p,m=k))(0)&&R

在线尝试!(具有1个索引的输出)

怎么样?

辅助功能 G 计算的所有排列 0ñ-1个,在哪里 ñ 是输入数组的隐式长度 一种[]

对于每个排列 p,我们计算:

ķ=ñ-1个+一世=0ñ-1个p一世-一种一世2
领先的唯一原因 ñ-1个 是我们重复使用内部计数器 G 保存几个字节,但对最终结果没有影响。

我们最终返回导致最小的排列 ķ



1

Python 2中149个 126 112字节

-23个字节,感谢Xcoder先生

-14个字节感谢xnor

from itertools import*
f=lambda a:min(permutations(range(len(a))),key=lambda x:sum(abs(a-b)for a,b in zip(x,a)))

在线尝试!

使用(0 ... n-1)的排列。


您可以切换到Python 2,这样就不再需要functools了。
Xcoder先生19年

reduce通常是多余的,尤其是在要添加内容的地方。我想你可以做sum(abs(p-q)for p,q in zip(x,a))
xnor19 19/09 / 14,9

0

没有任何排列组合

Python 3,238字节

def p(a,r,l):
 if r==[]:l+=[a];return
 for i in range(len(r)):
  p(a+[r[i]],r[:i]+r[i+1:],l)
def m(l):
 s=(float("inf"),0);q=[];p([],list(range(len(l))),q)
 for t in q:D=sum(abs(e-f)for e,f in zip(l,t));s=(D,t)if D<s[0]else s
 return s[1]

在线尝试!



0

Japt -g,12 个字节

Êõ á ñÈíaU x

尝试一下

对于0索引,请替换为前2个字节,m,以将数组映射到其索引。

Êõ á ñÈíaU x     :Implicit input of array U
Ê                :Length
 õ               :Range [0,Ê]
   á             :Permutations
     ñÈ          :Sort by
       í U       :  Interleave with U
        a        :  Reduce each pair by absolute difference
           x     :  Reduce resulting array by addition
                 :Implicit output of first sub-array

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.