順列のパリティ


14

バックグラウンド

順列のパリティはウィキペディアで定義されている次のように、次のとおりです。

順列σの符号または署名はsgn(σ)で示され、σが偶数の場合は+ 1、σが奇数の場合は-1として定義されます。

順列の符号は、次のように明示的に表現できます。

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

ここで、N(σ)はσの反転数です。

あるいは、置換σの符号は、転置の積への分解から次のように定義できます。

sgn(σ)=(−1)^ m

ここで、mは分解の転置の数です。

数学でギリシャ語のアルファベットスープが好きではない人のために、例(ウィキペディアから盗まれた)を使って定義を少し簡略化してみます。

入力配列{1, 2, 3, 4, 5}、およびその順列を考えてみましょう{3, 4, 5, 2, 1}。その順列に元の配列から取得するためには、インデックスを交換しなければならない0213、その後、2および4。これは独自のソリューションではありませんが、パリティは明確に定義されているため、すべての場合に機能します。

3つのスワップが必要なので、この順列にoddパリティを付けます。ご想像のとおり、偶数のスワップを必要とする順列にはevenパリティがあると言われています。

チャレンジ

あなたの課題は、置換のパリティを決定するために、できるだけ少ないバイトでプログラムを書くことです。プログラムまたは機能は以下を行う必要があります。

  • 置換の前後のセットを表す2つの入力配列(または文字列)を引数として受け入れます。
  • 順列が与えられると、偶数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の方がいいですか?
パトリックロバーツ

まあ、私たちは見るでしょう!
電卓

おやすみ!ここに戻ったときの提案をいくつか紹介します(ただし、自分で確認してください):([10], [10] -> e転置ゼロ)。[10 30 20], [30 20 10] -> e(2つの転置)。[10 30 20 40], [30 20 40 10] -> o(3つの転置)
ルイスメンドー

回答:


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
それは非常に小さいです。称賛!
パトリックロバーツ

6

MATL17 16バイト

デニスの提案により、1バイトが削除されました

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

これは は、言語の現在のバージョン(15.0.0)で機能します。

オンラインでお試しください

説明

これは、反転の観点からパリティの定義を使用します。反転は、最初の配列と比較して「間違った」順序にある​​2番目の配列の要素のペアです。最初の配列はソートする必要がないため、最初に配列をソートし、そのソートに必要な同じ再配置が2番目の配列に適用されます。次に、反転は、2番目の配列で増加していない要素のペアに対応します。

また、2つの入力配列を交換でき、結果は同じであることに注意してください。したがって、どの配列が「オリジナル」であると見なされ、どの配列が「置換」されるかは重要ではありません。

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
これは本当に賢い解決策です!
アレックスA.

@AlexA。ありがとう!回答を編集して、事前注文部分の機能を明確にしました。1つの配列を並べ替え、その並べ替えに必要な同じ再配置を他の配列に適用します。
ルイスメンドー

1
MATLにモジュラーインデックスを追加する必要があります。ここでは3バイト節約できます。
デニス

@Dennisはい、よく考えましたが...現在、負の値が異なる意味を持つ形式を使用しています。x(1:end-2)のサイズを明示的に示すことなく、フォームなどのインデックスを作成するために、それを選択しましたx。良い選択であったかどうかはわかりませんが、今すぐ変更するには遅すぎると思います:-)多分、モジュラーインデックスを追加する互換性のある方法を見つけるでしょう
ルイスメンドー

...現在の長さを超えるインデックスは、新しい値を割り当てるために使用されます。ただし、インデックスに0は「最後のエントリ」という意味があるため、1バイトを節約できます(増分を削除します)。アイデアをありがとう!
ルイスメンドー

5

オクターブ、56 52バイト

これまでのところ、このアプローチを使用している人はいないようです。基本的には、対応する置換行列の行列式を使用しているだけです。式det(eye(nnz(a))(a,:))は、vectorで定義された置換行列の行列式を返しますa。次に、結果に応じて、文字列から適切な文字を抽出するだけです。

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

2
行列式を使用することをお勧めします。オレ!
ルイスメンドー

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の答えと同じ方法。誇り高いhaskellerはでバイトを節約しましたcycle


1
cycle"eo"!!...代わりに"eo"!!mod(...)2、1バイト節約して書くことができます。
誇りに思って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'

2つの圧縮されたリストの反転ペアの数をカウントします。値(a,A)(b,B)同じインデックスの各リストからa<bA>B。これらの比較はa<b<M>A>B、リストMが任意の数よりも大きいというプロパティを使用してとして結合されます。次に、合計は2を法として取られ、eまたはに変換されoます。


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バイトのカリー化を忘れないでください
パトリックロバーツ

2

Mathematica、77バイト

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

同意する!


便利な機能、残念ながら長い名前!
パトリックロバーツ

迷惑ですよね?嫌いCyclesです。PermutationCyclesの名前のサイズを大きくし、さらにPermutationCycles愚かでCyclesオブジェクトを返します!`
CalculatorFeline

2

Mathematica、31バイト

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

Signature [list]は、リストの要素を標準的な順序で配置するために必要な順列の署名を提供します

最初に1つのリストを任意の順序(この場合は正規の順序)に並べ替え、このリストを最終リストに並べ替えることにより、1つのリストを他のリストに並べ替えることができます。2つのサブ順列の符号が等しい場合、全体の順列の符号は偶数です。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.