逆順列インデックス


17

前書き

リストの辞書式の順列n個の要素は、0から番号を付けることができ、N!-1.たとえば、3!= 6個の順列が(1,2,3)あろう(1,2,3)(1,3,2)(2,1,3)(2,3,1)(3,1,2)(3,2,1)

順列がリストに適用されると、その要素は順列の数字と同じ順序で並べられます。たとえば、yieldsに順列(2,3,1)を適用しl = (a,b,c)ます(l[2],l[3],l[1]) = (b,c,a)

順列の逆は、この操作を逆にする順列として定義されます。つまり、順列を適用し、その逆(またはその逆)は配列を変更しません。たとえば、yの逆(2,3,1)(3,1,2)(b,c,a)yieldsに適用されるため(a,b,c)です。

また、順列自体に適用される順列の逆は、整数1… nを生成します。たとえば、yields に適用(3,1,2)(2,3,1)ます(1,2,3)

私たちは今、関数定義revindXをインデックスと順列の逆置換の指標として)のx。(興味がある場合、これはA056019です。)

インデックスの順列ので、私は唯一の最後の変更のkリストの項目を場合に限っ 0≤ I < K!、我々は影響を与えずに、リストの先頭に任意の数の要素を追加することができますrevindIを)。したがって、リストの長さは結果に影響しません。

チャレンジ

あなたのタスクはrevindx)を実装することです。入力/引数として単一の非負整数xを取り、結果を単一の非負整数として出力/返す完全なプログラムまたは関数を作成します。

入力および出力は0インデックスまたは1インデックスの場合がありますが、これはそれらの間で一貫している必要があります。

インデックスによって順列を生成する、順列のインデックスを返す、または逆順列を見つける組み込み関数は禁止されています。(すべての順列または次の順列を生成するビルトインが許可されます。)

標準の規則が適用されます。

以下の例は0から始まります。

Input    Output
0        0
1        1
2        2
3        4
4        3
5        5
6        6
13       10
42       51
100      41
1000     3628
2000     3974
10000    30593
100000   303016

リファレンス実装(Python 3)

def revind(n):
    from math import factorial
    from itertools import permutations, count
    l = next(filter(lambda x: factorial(x) > n, count(1)))
    pms = list(permutations(range(l)))
    return [k for k in range(len(pms)) if tuple(pms[n][i] for i in pms[k]) == pms[0]][0]


1
この課題を理解するには、逆順列の定義を調べる必要がありました。あなたの例は(a,b,c)非常に不明瞭です。逆順列とは何かを適切に説明してください。
16年

@Fatalizeこれは簡単に説明するのはちょっと難しいです。今はまし?
-PurkkaKoodari

Jellyには、配列のインデックスを対応する値でソートするアトム(グレードアップ)があります。これはたまたま1、…、nの順列反転させますが、他の順列では機能しません。禁じられビルトイン?
デニス

@デニスハード質問。厳密には、厳密に増加するリストに適用された後、順列の逆を見つけます。したがって、許可されていないと言います。(誰かが厳密に意見を異にする場合は、コメントしてください。コミュニティが望むならこれを変更するかもしれません。)
PurkkaKoodari

回答:


5

ゼリー、6バイト

ịŒ!⁺iR

I / Oは1ベースのインデックスを使用します。 非常に遅く、メモリを大量に消費します。

検証

入力が8を超えない限り= 40320、配列[1、…、8]のすべての順列を考慮するだけで十分です。最後のテストケースでは、の順列 [1、…、9]十分です。

最初の8個または9個の正の整数の順列のみを考慮するわずかに変更されたコードを使用すると、オンラインで試すことができます!または、残りのすべてのテストケースを検証します

使い方

ịŒ!⁺iR  Main link. Argument: n

 Œ!     Yield all permutations of [1, ..., n].
ị       At-index; retrieve the n-th permutation.
   ⁺    Duplicate the Œ! atom, generating all permutations of the n-th permutation.
     R  Range; yield [1, ..., n].
    i   Index; find the index of [1, ..., n] in the generated 2D array.

代替アプローチ、6バイト(無効)

Œ!Ụ€Ụi

それは同じくらい長く、禁じられたグレードアップアトムを使用します間違いなく)より慣用的です。

8(最後のテストケースの場合は9)を追加することで、実際にオンラインで試すことができます!

使い方

Œ!Ụ€Ụi  Main link. Argument: n

Œ!      Yield all permutations of [1, ..., n].
  Ụ€    Grade up each; sort the indices of each permutation by the corresponding
        values. For a permutation of [1, ..., n], this inverts the permutation.
    Ụ   Grade up; sort [1, ..., n!] by the corresponding inverted permutations
        (lexicographical order).
     i  Index; yield the 1-based index of n, which corresponds to the inverse of
        the n-th permutation.

6

Mathematica、74バイト

Max@k[i,Flatten@Outer[i=Permutations[j=Range@#];k=Position,{i[[#]]},j,1]]&

1インデックスを使用します。非常に非効率的です。(入力が〜11GBのメモリを使用する場合11

説明

j=Range@#

1からNまでのリストを生成しjます。それをに保存します。

i=Permutations[...]

のすべての順列を見つけますj。に保存しiます。

k=Position

保管Position中の関数をk。(Position再度使用するときにバイト数を減らすため)

Flatten@Outer[...,{i[[#]]},j,1]

N番目の順列の逆順列を見つけます。

Max@k[i,...]

で逆順列のkPosition)を見つけるi(すべての順列)

組み込みの使用、46 43バイト

a[(a=Ordering)/@Permutations@Range@#][[#]]&

1インデックス付き。


2
「逆順列を発見するビルティンは禁止されています」
グレッグマーティン

@GregMartin、ああ、どういうわけかその部分を見逃し、「順列のインデックスを返す」部分だけを見ました。愚かな...新しいコードにはその問題はありません。
ジョンファンミン

うん、見逃しがちだったと思う。74バイト—まだかなり印象的です!
グレッグマーティン

5

MATL、15バイト

:Y@tGY)Z)G:=!Af

入力と出力は1ベースです。

@MartinEnderのCJamの回答に似ていますにいますが、考えられるすべての順列を入力で指定された順列で構成し、どちらが恒等置換になっているかを確認することにより、逆順列を見つけます。

入力用のオンラインコンパイラでメモリが不足する 10

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

説明

:      % Implicitly input N. Push range [1 2 ... N]
Y@     % Matrix witll all permutations of size N. Each permutation is a row
tGY)   % Duplicate. Get the N-th row
Z)     % Use that as a column index into the matrix of all permutations
G:=    % Compare each row with [1 2 ... N]
!Af    % Find index of the row that matches. Implicitly display

5

Pyth、12バイト

xJ.phQxL@JQh

テストスイート

0がインデックス付けされました。

説明:

xJ.phQxL@JQh
xJ.phQxL@JQhQ    Implicit variable introduction
                 Q = eval(input())
  .phQ           Form all permutations of range(Q+1), namely [0, 1, .. Q]
 J               Save to J.
        @JQ      Take the Qth element of J.
      xL   hQ    Map all elements of [0, 1, ..., Q] to their index in above
x                Find the index in J of the above.

5

05AB1E14 13バイト

非常にメモリ効率が悪い。メモリ効率がさらに向上しました(ただし1バイト短くなりました)。
0から始まる範囲。CP-1252エンコードを
使用します。

ƒ¹ÝœD¹èNkˆ}¯k

オンラインでお試しください! または変更されたテストスイートとして

説明

ƒ               # for N in range[0 .. x]
 ¹ÝœD           # generate 2 copies of all permutations of range[0 .. x]
     ¹è         # get permutation at index x
       Nkˆ      # store index of N in that permutation in global list
         }      # end loop
          ¯k    # get index of global list (inverse) in list of permutations

4

CJam、16バイト

ri_)e!_@=_$\f#a#

インデックスは0から始まります。

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

私はこれよりも非効率的ではありません...入力のJavaのデフォルト設定でメモリが不足します8(しかし、十分な数の時間とメモリの宇宙が与えられれば、原則として任意の入力に対して動作します)。

説明

ri    e# Read input and convert to integer N.
_)e!  e# Duplicate N, get all permutations of [0 1 ... N].
_@=   e# Duplicate permutations, get the Nth permutation.
_$    e# Duplicate and sort to get the sorted range [0 1 ... N].
\f#   e# For each of these values, get its index in the Nth permutation.
      e# This inverts the permutation.
a#    e# Find the index of this new permutation in the list of all permutations.

3

ギャップ、108バイト

h:=l->n->PositionProperty(l,p->l[n]*p=());
f:=n->h(Set(SymmetricGroup(First([1..n],k->Factorial(k)>=n))))(n);

1インデックス付き。改行はカウントされず、必要ありません。最終機能を名前に割り当てる必要はありませんが、...

hは、順列のリストとそのリストへのインデックスを取り、逆順列のインデックスを返すカリー化された関数です。制限なしでPosition(l,l[n]^-1)f十分に大きな対称グループのソートされた順列と与えられたn

を書くだけでSymmetricGroup(n)、9までの値に対して関数を計算することができます。すでにはるかに小さなソリューションが存在するため、これを行うことができます。

gap> f(100001);
303017

99未満の引数に対して機能する、本当に効率的な0インデックス付きソリューション!(1バイトのコストで999未満の引数で動作するようにできます)は次のとおりです。

f:=function(n)
 local m,l,p,i,g;
 m:=First([1..99],k->Factorial(k)>n);
 g:=List([m-1,m-2..0],Factorial);
 l:=[1..m];
 p:=[];
 for i in g do
  Add(p,Remove(l,QuoInt(n,i)+1));
  n:=n mod i;
 od;
 return Sum(ListN(List([1..m],i->Number([1..Position(p,i)],j->p[j]>i)),g,\*));
end;

空白を削除すると、255バイトになります。


よくやった!私もいくつかの効率的なソリューションを得たいと思っていました。
-PurkkaKoodari

3

JavaScriptの(ES6)、163の 120 110バイト

f=(n,a=[],i=0,r=0,[j,...b]=a)=>n?a.splice(n%-~i,0,i)|f(n/++i|0,a,i):i?f(n,b,i-1,b.reduce((r,k)=>r+=k>j,r*i)):r
<input type=number min=0 oninput=o.textContent=f(+this.value)><pre id=o>

0インデックス。インデックスを順列に変換し、逆に変換してから、インデックスに戻すことで機能します。編集:f順列を反転および逆にし、逆の順列をgインデックスに変換することで約25%節約しました。2つの再帰呼び出しを1つの関数に結合することにより、さらに10バイトを節約しました。ゴルフをしていない:

function index(n) {
    var a = [0];
    for (var i = 1; n = Math.floor(n / i); i++) {
        var j = i - n % (i + 1);
        for (var k = 0; k < i; k++) {
            if (a[k] > j) a[k]++;
        }
        a.push(j);
    }
    a = [...a.keys()].map(k => a.indexOf(k));
    while (i) {
        n *= i--;
        j = a.pop();
        for (k = 0; k < i; k++) {
            if (a[k] > j) n++;
        }
    }
    return n;
}

1
@JonathanAllan申し訳ありませんが、最後の9バイトの節約を見つけたと思いましたが、徹底的にテストできませんでした。以前のバージョンに戻しました。
ニール

実装が非常に素直になりました。
ジョナサンアラン

1
私が得れば@JonathanAllanはさらにパッあることが判明f代わりの順列を反転させるためにg...
ニール

3

J、55 50バイト

g=:/:~i.@#
[:(#\.#.+/@(<{.)\.)@g(-i.)@>:g@g@,/@#:]

順列指数に関するエッセイに基づいて。

このコードはメモリを必要としますnが、リストの時間を並べ替えて各インデックスの時間をn検索するため、より多くの時間を使用しnます。

/:リストのグレードと順列の逆数を見つけることができるビルトインを使用すると、より効率的な42バイトのソリューションがあります。

[:(#\.#.+/@(<{.)\.)@/:(-i.)@>:/:@/:@,/@#:]

このバージョンは、105秒を必要とする他のバージョンと比較した場合、最後のテストケースを計算するのに44秒しか必要ありません。

使用法

   g =: /:~i.@#
   f =: [:(#\.#.+/@(<{.)\.)@g(-i.)@>:g@g@,/@#:]
   (,.f"0) 0 1 2 3 4 5 6 13 42 100 1000 2000 10000
    0     0
    1     1
    2     2
    3     4
    4     3
    5     5
    6     6
   13    10
   42    51
  100    41
 1000  3628
 2000  3974
10000 30593
   timex 'r =: f 100000'
105.787
   r
303016

ゴルフ言語では触れられないメモリ効率のために+1。
魔法のタコ

2

ゼリー14 13 9 バイト

-4バイト、@ Dennisに感謝します(彼、回答でクイックを使用してさらにゴルフをしました)

Œ!ịịŒ!$iR

別の非常に遅い実装。
ここでは1ベースのインデックス付けが採用されているため、期待される結果は次のとおりです。

input:  1 2 3 4 5 6 7 8  9 10 11
output: 1 2 3 5 4 6 7 8 13 19  9

TIOはの入力で強制終了するため、オンラインIDEリンクを設定することさえ意味がありません10。ローカル結果(最後は非常に遅く、大量のメモリが必要です!):

C:\Jelly\jelly-master>python jelly -fu D:\jelly_scripts\revPerm.txt 1
1
C:\Jelly\jelly-master>python jelly -fu D:\jelly_scripts\revPerm.txt 2
2
C:\Jelly\jelly-master>python jelly -fu D:\jelly_scripts\revPerm.txt 3
3
C:\Jelly\jelly-master>python jelly -fu D:\jelly_scripts\revPerm.txt 4
5
C:\Jelly\jelly-master>python jelly -fu D:\jelly_scripts\revPerm.txt 5
4
C:\Jelly\jelly-master>python jelly -fu D:\jelly_scripts\revPerm.txt 6
6
C:\Jelly\jelly-master>python jelly -fu D:\jelly_scripts\revPerm.txt 7
7
C:\Jelly\jelly-master>python jelly -fu D:\jelly_scripts\revPerm.txt 8
8
C:\Jelly\jelly-master>python jelly -fu D:\jelly_scripts\revPerm.txt 9
13
C:\Jelly\jelly-master>python jelly -fu D:\jelly_scripts\revPerm.txt 10
19
C:\Jelly\jelly-master>python jelly -fu D:\jelly_scripts\revPerm.txt 11
9

どうやって?

Œ!ịịŒ!$iR - Main link 1: n
      $   - last two links as a monad
    Œ!    -     permutations of implicit range [1,2,3,...,n]
   ị      -     value at index n (the nth permutation)
Œ!        - permutations of implicit range [1,2,3,...,n]
  ị       - value at index (the indexes of the permuted values in the nth permutation)
       i  - index of
        R - range [1,2,3,...,n]

注:順列の検索と逆の両方に同じ順序を使用しているため、順列をソートする必要はありません。


私の携帯電話からテストすることはできませんが、リンク2を削除してメインリンクを作成することはできませんÇịịÇ$iRか?
デニス

実際には、RŒ!は暗黙的であるためŒ!ịịŒ!$iR、仕事をする必要があります。
デニス

ええ、これは友人に会う前に非常に急いだエントリーでした。
ジョナサンアラン

2

Python 2、116 114バイト

from itertools import*
def f(n):r=range(n+1);l=list(permutations(r));print l.index(tuple(l[n].index(v)for v in r))

repl.it

0ベース。低速でメモリを大量に消費しますが、バイトは不足しています。


順列関数を使用しない; メモリと時間の両方が効率的です。289 285バイト

@Christian Sieversのおかげで-4バイト(完全な順列が既に形成されています)

h=lambda n,v=1,x=1:v and(n>=v and h(n,v*x,x+1)or(v,x-1))or n and h(n-1,0,n*x)or x
i=lambda p,j=0,r=0:j<len(p)and i(p,j+1,r+sum(k<p[j]for k in p[j+1:])*h(len(p)-j-1,0))or r
def f(n):t,x=h(n);g=range(x);o=g[:];r=[];exec"t/=x;x-=1;r+=[o.pop(n/t)];n%=t;"*x;return i([r.index(v)for v in g])

私はそれがゴルフのコードだと知っていますが、@ Pietu1998は効率的な実装にも興味があると思います。

repl.it実際の動作をご覧ください

この用途には、より多くのために、比較参照実装よりもバイトをしながらn=5000000

ref:    6GB 148s  
this: 200KB <1ms

f 逆インデックス関数です。

f最初の上の次の階乗を取得ntおよびその階乗で、整数x呼び出すことによってh(n)、およびセットg=range(x)、順列を占めるようになるアイテムをo=g[:]、および順列ホルダーr=[]

次に、の階乗ベース表現のインデックスをアイテムから順番に取得し、それらをに追加することnによりpop、インデックスで順列を構築します。階乗基底表現はdivとmodで見つかり、where はdiv'd で減少しますnornttxx1

最後に、逆順列を呼び出しiて逆順列のインデックスを見つけます。[r.index(v)for v in g]

h は、非負整数の階乗を計算するか、非負整数の上の次の階乗とその階乗を作る整数の両方を計算するための二重目的関数です。

それには、デフォルトの状態だv=1と、それは乗算することで、後者んvx(も当初1)とインクリメントxされるまでn、それは、少なくとも大きなようです返すvx-1タプルに。

計算するためにn!1つのコールh(n,0)x(最初1)によってn及びデクリメントをnするまでnである0ことが戻ったときx

iは、各インデックスの階乗ベースの階乗の積を合計することpにより、項目の順列の辞書編集インデックスを提供し、インデックスの右にあるアイテムがそのインデックスの値よりも少ないアイテムの数を提供します。[0,1,...n]h(len(p)-j-1,0)sum(k<p[j]for k in p[j+1:])


順列を構築するとき、最後の項目を特別なケースに入れる必要はないと思います。255バイトのGAPソリューションには含まれていません。
クリスチャンシーバーズ

そうしないとゼロ除算エラーが発生するため、最後に個別に追加しt/=xます。
ジョナサンアラン

見るために私にしばらく時間がかかった:ループはすでにそれをすべて行い、あなたは置き換えることができます(r+o)によってr
クリスチャンシーバーズ

ええ、あなたは正しいです!どうもありがとうございます。
ジョナサンアラン

1

Python 2、130 129バイト

p=lambda x,k,j=1:x[j:]and p(x,k/j,j+1)+[x.pop(k%j)]
n=input();r=range(n+2);k=0
while[p(r*1,n)[i]for i in p(r*1,k)]>r:k+=1
print k

1

実際18 11バイト

この回答では、DennisのJelly回答のアルゴリズムを使用していますが、インデックスは0です。ゴルフの提案を歓迎します!オンラインでお試しください!

4╞r;)╨E╨♂#í

アンゴルフ

      Implicit input n.
4╞    Push 4 duplicates of n. Stack: n, n, n, n
r;)   Push the range [0...n], and move a duplicate of that range to BOS for later.
╨E    Push the n-length permutations of [0...n] and get perm_list[n].
        Stack: perm_list[n], n, [0...n]
╨     Push the n-length permutations of perm_list[n].
♂#    Convert every "list" in the zip to an actual list.
        Stack: perm(perm_list[n]), [0...n]
í     Get the index of [0...n] in the list of permutations of perm_list[n].
      Implicit return.
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.