排列奇偶


14

背景

所述置换的奇偶性由维基百科所定义,如下:

排列σ的符号表示为sgn(σ),如果σ为偶数,则定义为+1,如果σ为奇数,则定义为-1。

排列的符号可以明确表示为

sgn(σ)=(-1)^ N(σ)

其中,N(σ)是σ中的求逆数。

替代地,可以从置换成分解为换位的乘积来定义置换的符号

sgn(σ)=(-1)^ m

其中,m是分解中的换位数。

对于那些在数学上不喜欢希腊字母汤的人,我将尝试通过一个示例(也从维基百科窃取)来简化定义。

考虑输入数组{1, 2, 3, 4, 5},以及它的一个排列,比如说{3, 4, 5, 2, 1}。为了从原始数组获取其排列,您必须交换索引0213,然后交换24。尽管这不是唯一的解决方案,但奇偶校验定义明确,因此适用于所有情况。

由于需要进行3次交换,因此我们用odd奇偶校验标记此排列。如您所料,要求偶数交换的排列具有even奇偶性。

挑战

您面临的挑战是编写尽可能少的字节的程序以确定排列的奇偶性。您的程序或函数必须:

  • 接受两个输入数组(或字符串)作为参数,分别表示排列前后的集合。
  • 给定排列,返回或打印e偶数或o奇数字符。
  • 应该假设数组或字符串中的所有索引都具有唯一值。

测试用例

假设您声明了一个名为的函数f

f([10], [10]) == "e"
f([10, 30, 20], [30, 20, 10]) == "e"
f([10, 30, 20, 40], [30, 20, 40, 10]) == "o"

这是,以字节为单位的最短程序胜出!


4
人们不会喜欢严格的输出格式。真为偶,假为奇如何?(或相反)
CalculatorFeline

我实际上希望保留我指定的输出格式,除非其他人确实对此感到困扰。编辑保留,我会妥协的。
帕特里克·罗伯茨

@CatsAreFluffy更好吗?
帕特里克·罗伯茨

好吧,我想我们会看到的!
CalculatorFeline

晚安!以下是当您回到此状态时的一些建议(但请检查一下自己):([10], [10] -> e零换位)。[10 30 20], [30 20 10] -> e(两个换位)。[10 30 20 40], [30 20 40 10] -> o(三个换位)
路易斯·门多

Answers:


5

果冻,13 12字节

żṗ2</€⁺Sị“oe

在线尝试!

怎么运行的

żṗ2</€⁺Sị“oe  Main link. Arguments: A, B (lists)

ż             Zip A with B. Yields an array of pairs [x, σ(x)].
 ṗ2           Generate all pairs [[x, σ(x)], [y, σ(y)]].
   </€        Reduce each pair by </€.
              This maps [[x, σ(x)], [y, σ(y)]] to [x < y, σ(x) < σ(y)].
      ⁺       Repeat the previous link, i.e., execute </€ once more.
              This maps [x < y, σ(x) < σ(y)] to ((x < y) < (σ(x) < σ(y))), which is
              true if and only if x > y and σ(x) < σ(y).
       S      Sum. This counts the number of inversions.
        ị“oe  Retrieve the letter at the corresponding index.
              Indexing is 1-based and modular, so an odd sum retrieves the first
              letter, an even sum the second.

1
那真是太小了。荣誉!
Patrick Roberts

6

MATL17 16字节

由于Dennis的建议,删除了1个字节

2$St!<Rz2\'oe'w)

这适用于该语言的当前版本(15.0.0)

在线尝试

说明

这使用反转定义的奇偶校验。反转是第二个数组中与第一个数组相比处于“错误”顺序的一对元素。由于不需要对第一个数组进行排序,因此我们首先对其进行排序,然后将排序所需的相同重排应用于第二个数组。然后,反转对应于第二数组中未增加的一对元素。

还要注意,两个输入数组可以交换,结果是相同的。因此,将哪个数组视为“原始”数组和将哪个“置换”数组并不重要。

2$S     % implicitly take two row vectors. Sort second and apply the indices
        % of that sorting to the first
t!      % duplicate. Transpose into column vector
<       % true for elements of the column vector that exceed those of the 
        % row vector. Gives a 2D array with all pairs of comparisons
R       % keep only upper triangular part of that array
z       % number of nonzero elements. This is the number of inversions
2\      % parity of that number: gives 0 or 1
'oe'w   % push string 'eo' below the top of the stack
)       % apply index to produce 'e' or 'o'. An index 1 refers to the first
        % element, whereas 0 refers to the last. Implicitly display 

1
这是一个非常聪明的解决方案!
Alex A.

@AlexA。谢谢!我已经编辑了答案以阐明预排序部分的作用:我们对一个数组进行排序,然后将排序所需的相同重排应用于另一个数组。
Luis Mendo

1
您应该向MATL添加模块化索引。这样可以节省3个字节。
丹尼斯

@Dennis是的,我经常想到这一点...但是目前,它使用负值含义不同的格式。我选择这样做是为了具有形式x(1:end-2)等的索引,而没有明确指出的大小x。不确定这是否是一个不错的选择,但我想现在更改为时已晚:-)也许我会找到一种兼容的方式来添加模块化索引
Luis Mendo

...并且超过当前长度的索引用于分配新值。但是索引0确实具有“最后一个入口”的含义,因此我可以保存一个字节(删除增量)。谢谢你的主意!
Luis Mendo

5

八度,56 52字节

到目前为止,似乎没有人在使用这种方法:基本上,我只是在使用相应置换矩阵的行列式。该表达式det(eye(nnz(a))(a,:))返回由向量定义的置换矩阵的行列式a。然后,只需根据结果从字符串中提取正确的字符即可。

p=@(v)eye(nnz(v))(v,:);@(a,b)'ole'(det(p(a)*p(b))+2)

2
使用行列式的好主意。好极了!
Luis Mendo

5

Haskell,58个字节

k%l|m<-zip k l=cycle"eo"!!sum[1|(a,b)<-m,(c,d)<-m,a<c,b>d]

用法:

*Main> [8,3,5]%[5,3,8]
'o'

我的Python回答相同的方法。骄傲的哈斯克勒用节省了一点钱cycle


1
您可以写cycle"eo"!!...代替"eo"!!mod(...)2,节省一个字节。
骄傲的haskeller

4

Python 2,68个字节

lambda*M:"eo"[sum(a<b<M>A>B for a,A in zip(*M)for b,B in zip(*M))%2]

用法:

>>> f=lambda*M:"eo"[sum(a<b<M>A>B for a,A in zip(*M)for b,B in zip(*M))%2]
>>> f([8,3,5],[5,3,8])
'o'

计算两个压缩列表的反转对的数量,即 值,(a,A)(b,B)使用a<b和在同一索引的每个列表中A>Ba<b<M>A>B使用列表M大于任何数字的属性,将这些比较合并为。然后将总和取模2并变成eo


3

JavaScript(ES6),73个字节

(a,b)=>"eo"[r=0,g=a=>a.map((e,i)=>a.slice(i).map(d=>r^=d<e)),g(a),g(b),r]

由于我们仅对奇偶校验感兴趣,因此任何重复的换位都将被抵消。方便地,JavaScript的数组下标不是多维的。


1
逗号很有趣的地方..不知道你能做到这一点。不要忘记对-1字节进行计数
Patrick Roberts

2

Mathematica,77个字节

If[Mod[Plus@@Length/@(Join[{0},#]&)/@PermutationCycles[#][[1]],2]==0,"e","o"]&

我同意!


方便的功能,可惜名字太长了!
Patrick Roberts

烦人吧?我讨厌Cycles。它扩大了PermutationCycles的名称的大小,甚至PermutationCycles很笨拙,还返回了一个Cycles对象!`
CalculatorFeline

2

Mathematica,31个字节

If[Tr[Signature/@{##}]==0,o,e]&

Signature [list]给出将列表元素按规范顺序放置所需的排列签名

我们可以将一个列表重新排序为另一个列表,方法是先将一个列表重新排序为任何顺序(在这种情况下为规范顺序),然​​后将此列表重新排列为最终列表。如果两个子排列的符号相等,则整体排列的符号是偶数。

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.