Inverser Permutationsindex


17

Einführung

Die lexikographischen Permutationen einer Liste mit n Elementen können von 0 bis n nummeriert werden ! - 1. Zum Beispiel die 3! = 6 Permutationen (1,2,3)wären (1,2,3), (1,3,2), (2,1,3), (2,3,1), (3,1,2), (3,2,1).

Wenn eine Permutation auf eine Liste angewendet wird, werden ihre Elemente in derselben Reihenfolge wie die Nummern in der Permutation sortiert. Zum Beispiel die Permutation (2,3,1)auf l = (a,b,c)Ausbeuten anwenden (l[2],l[3],l[1]) = (b,c,a).

Die Umkehrung einer Permutation ist definiert als die Permutation, die diesen Vorgang umkehrt, dh eine Permutation anwendet und dann durch ihre Umkehrung (oder umgekehrt) das Array nicht verändert. Zum Beispiel kann die Inverse von (2,3,1)IS (3,1,2), da das Aufbringen (b,c,a)Ausbeuten (a,b,c).

Auch die Umkehrung einer Permutation, die auf die Permutation selbst angewendet wird, ergibt die ganzen Zahlen 1… n . Zum Beispiel (3,1,2)auf (2,3,1)Renditen anwenden (1,2,3).

Wir definieren nun die Funktion revind ( x ) als Index der inversen Permutation der Permutation mit dem Index x . (Dies ist A056019 , wenn Sie interessiert sind.)

Da eine Permutation mit Index i nur die letzten k Elemente der Liste ändert, wenn 0 ≤ i < k ! Ist , können wir eine beliebige Anzahl von Elementen an den Anfang der Liste setzen, ohne revind ( i ) zu beeinflussen. Daher hat die Länge der Liste keinen Einfluss auf das Ergebnis.

Herausforderung

Ihre Aufgabe ist es, revind ( x ) zu implementieren . Sie schreiben ein vollständiges Programm oder eine Funktion, die eine einzelne nichtnegative Ganzzahl x als Eingabe / Argument verwendet und das Ergebnis als einzelne nichtnegative Ganzzahl ausgibt / zurückgibt.

Die Eingabe und Ausgabe können 0-indiziert oder 1-indiziert sein, dies muss jedoch zwischen ihnen konsistent sein.

Builtins, die Permutationen nach Index generieren, den Index einer Permutation zurückgeben oder die inverse Permutation finden, sind gesperrt. (Builtins, die alle Permutationen oder die nächste Permutation erzeugen, sind erlaubt.)

Es gelten die Standardregeln für .

Beispiele

Die folgenden Beispiele sind 0-indiziert.

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

Referenzimplementierung (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
Ich musste die Definition der inversen Permutation nachschlagen, um diese Herausforderung zu verstehen. Ich finde dein Beispiel (a,b,c)extrem unübersichtlich. Bitte erläutern Sie genau, was eine inverse Permutation ist.
Fatalize

@Fatalize Das ist schwer zu erklären. Besser jetzt?
PurkkaKoodari

Jelly hat das Atom (grade up), das die Indizes eines Arrays nach ihren entsprechenden Werten sortiert. Dies geschieht, um eine Permutation von 1, ..., n zu invertieren , funktioniert jedoch nicht für andere Permutationen. Ist eine verbotene eingebaut?
Dennis

@ Tennis Harte Frage. Technisch betrachtet findet es die Umkehrung jeder Permutation, nachdem sie auf eine streng aufsteigende Liste angewendet wurde. Deshalb werde ich sagen nicht erlaubt. (Wenn jemand nicht einverstanden ist,
zögern Sie nicht

Antworten:


5

Gelee , 6 Bytes

ịŒ!⁺iR

E / A verwendet eine 1-basierte Indizierung. Sehr langsam und speicherhungrig.

Nachprüfung

Solange der Eingang 8 nicht überschreitet ! = 40320 ist es ausreichend, alle Permutationen des Arrays [1,…, 8] zu berücksichtigen . Für den letzten Testfall genügen die Permutationen von [1,…, 9] .

Mit leicht modifiziertem Code, der nur die Permutationen der ersten 8 oder 9 positiven Ganzzahlen berücksichtigt , können Sie es online ausprobieren! oder überprüfen Sie alle verbleibenden Testfälle .

Wie es funktioniert

ịŒ!⁺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.

Alternativer Ansatz, 6 Bytes (ungültig)

Œ!Ụ€Ụi

Es ist genauso lang und verwendet das verbotene Atom der höheren Klasse , aber es ist (wohl) idiomatischer.

Durch das Voranstellen von 8 (oder 9 für den letzten Testfall) können wir es tatsächlich online ausprobieren !

Wie es funktioniert

Œ!Ụ€Ụ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 Bytes

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

Verwendet 1-Indizierung. Sehr ineffizient. (Verwendet ~ 11 GB Speicher, wenn der Eingang ist 11)

Erläuterung

j=Range@#

Erstellen Sie eine Liste von 1 bis N. Speichern Sie diese in j.

i=Permutations[...]

Hier finden Sie alle Permutationen von j. Bewahren Sie das in i.

k=Position

Speichern Sie die PositionFunktion in k. (um die Anzahl der Bytes bei Positionerneuter Verwendung zu verringern )

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

Finden Sie die inverse Permutation der N-ten Permutation.

Max@k[i,...]

Finde das k( Position) der inversen Permutation in i(allen Permutationen)

Mit eingebauten 46 43 Bytes

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

1-indiziert.


2
"Builtins, die ... die inverse Permutation finden, sind verboten"
Greg Martin

@ GregMartin, ah, ich habe diesen Teil irgendwie verpasst und nur den Teil "Rückgabe des Index einer Permutation" gesehen. Dumme ich ... Der neue Code hat dieses Problem nicht.
JungHwan Min

Ja, ich stimme zu, es war leicht zu übersehen. 74 Bytes - immer noch ziemlich beeindruckend!
Greg Martin

5

MATL , 15 Bytes

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

Eingang und Ausgang sind 1-basiert.

Entspricht der CJam-Antwort von @ MartinEnder, ermittelt jedoch die inverse Permutation, indem alle möglichen Permutationen mit der in der Eingabe angegebenen zusammengesetzt und die identitätsgebundene Permutation ermittelt werden.

Im Online-Compiler ist nicht genügend Speicher für die Eingabe vorhanden 10.

Probieren Sie es online!

Erläuterung

:      % 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 Bytes

xJ.phQxL@JQh

Testsuite

0 indiziert.

Erläuterung:

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

05AB1E , 14 13 Bytes

Sehr ineffizienter Speicher. Jetzt noch mehr Speicher ineffizient (aber 1 Byte kürzer).
0-basierter Bereich.
Verwendet CP-1252- Codierung.

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

Probieren Sie es online! oder als modifizierte Testsuite

Erläuterung

ƒ               # 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 Bytes

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

Indizes sind 0-basiert.

Probieren Sie es online!

Ich werde nicht viel ineffizienter als dies ... mit Javas Standardeinstellungen für Eingaben größer als 8(funktioniert aber im Prinzip für beliebige Eingaben bei einer ausreichenden Anzahl von Zeit- und Speicheruniversen).

Erläuterung

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

GAP , 108 Bytes

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

1-indiziert. Zeilenumbrüche werden nicht gezählt, sie werden nicht benötigt. Ich muss die endgültige Funktion nicht wirklich einem Namen zuweisen, aber ...

hist eine Curry-Funktion, die eine Liste von Permutationen und einen Index in diese Liste aufnimmt und den Index der inversen Permission zurückgibt. Ohne Einschränkungen würde ich einfach tun Position(l,l[n]^-1). fruft diese Funktion mit den sortierten Permutationen einer ausreichend großen symmetrischen Gruppe und der gegebenen auf n.

Ich könnte einfach schreiben SymmetricGroup(n), dann könnte die Funktion für Werte bis 9 berechnet werden. Da es bereits viel kleinere Lösungen gibt, bevorzuge ich dies:

gap> f(100001);
303017

Eine wirklich effiziente Lösung mit 0 Indizes, die für Argumente unter 99 geeignet ist! (und kann auf Kosten eines Bytes für Argumente unter 999 verwendet werden!)

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;

Nach dem Löschen des Leerzeichens hat dies 255 Bytes.


Gute Arbeit! Ich hoffte, auch einige effiziente Lösungen zu erhalten.
PurkkaKoodari

3

JavaScript (ES6), 163 120 110 Byte

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-indiziert. Konvertiert den Index in eine Permutation, invertiert ihn und konvertiert ihn dann zurück in einen Index. Bearbeiten: Durch fInvertieren und Umkehren der Permutation und anschließendes gZurückkonvertieren der umgekehrten Permutation in einen Index wurden ca. 25% eingespart . Es wurden weitere 10 Byte gespeichert, indem die beiden rekursiven Aufrufe zu einer einzigen Funktion kombiniert wurden. Ungolfed:

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 Entschuldigung, ich dachte, ich hätte in letzter Sekunde 9 Byte gespart, konnte es aber nicht gründlich testen. Ich habe meine vorherige Version wiederhergestellt.
Neil

Sehr schnelle Umsetzung jetzt.
Jonathan Allan

1
@JonathanAllan Es stellt sich heraus, dass es noch aufregender ist, wenn ich fdie Permutation umkehren kann, anstatt g...
Neil,

3

J 55 50 Bytes

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

Basierend auf dem J Essay on Permutation Index .

Dieser Code benötigt nur Speicher in der Größenordnung von, benötigt njedoch mehr Zeit, da er die Listenzeiten sortiert nund nach njedem Index durchsucht .

Mit dem eingebauten Code, /:der den Grad einer Liste und die Umkehrung einer Permutation findet, gibt es eine 42-Byte-Lösung, die effizienter ist.

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

Diese Version benötigt nur 44 Sekunden, um den letzten Testfall im Vergleich zu dem anderen zu berechnen, der 105 Sekunden benötigt.

Verwendung

   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 für eine Speichereffizienz, die Golfsprachen nicht erreichen können.
Magic Octopus Urn

2

Jelly , 14 13 9 Bytes

-4 Bytes dank @Dennis (den er mit dem Quick in seiner Antwort weiter ausbaute )

Œ!ịịŒ!$iR

Eine weitere sehr langsame Implementierung.
Hier wird eine 1-basierte Indizierung verwendet, daher sind die erwarteten Ergebnisse:

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

Es hat keinen Sinn, einen Online-IDE-Link einzurichten, da TIO bei einem Eingang von tötet 10. Lokale Ergebnisse (Letzteres ist sehr langsam und erfordert eine Tonne Speicher!):

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

Wie?

Œ!ịịŒ!$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]

Hinweis: Es ist nicht erforderlich, die Permutationen zu sortieren, da sowohl die Permutation als auch und umgekehrt in derselben Reihenfolge ermittelt werden.


Sie können es nicht von meinem Telefon aus testen, aber konnten Sie Link 2 nicht entfernen und den Haupt-Link erstellen ÇịịÇ$iR?
Dennis

Eigentlich ist das RVorher Œ!implizit, Œ!ịịŒ!$iRsollte also die Arbeit erledigen.
Dennis

Ja, dies war ein sehr eiliger Eintrag, bevor ich Freunde traf.
Jonathan Allan

2

Python 2, 116 114 Bytes

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-basiert. Langsam und speicherhungrig, aber wenig Bytes.


Verwenden Sie keine Permutationsfunktionen. speicher und zeiteffizient. 289 285 Bytes

-4 Bytes dank @Christian Sievers (volle Permutation bereits gebildet)

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])

Ich weiß, dass es Codegolf ist, aber ich denke, dass @ Pietu1998 auch an effizienten Implementierungen interessiert ist.

Sehen Sie es in Aktion bei repl.it

Dabei werden mehr Bytes als bei der Referenzimplementierung verwendet, verglichen mit n=5000000:

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

f ist die Rückwärtsindexfunktion.

fzuerst wird das nächste faktorielles oben n, tund die ganze Zahl , dessen Fakultäts das heißt, xdurch den Aufruf h(n)und setzen g=range(x), die Elemente , die die Permutation bilden werden, o=g[:]und die Permutation Halter,r=[]

Als nächstes wird die Permutation am Index konstruiert, nindem popdie Indizes der faktoriellen Basisrepräsentation nder Elemente der Reihe nach aus den Elementen gebildet ound an diese angehängt werden r. Die faktorielle Basisdarstellung wird durch div und mod gefundener nmit tdenen tsich durch div'd xund xdekrementiert bis auf 1.

Schließlich findet es den Index der umgekehrten Permutation, indem es imit der umgekehrten Permutation aufruft ,[r.index(v)for v in g]

h ist eine Doppelfunktion zum Berechnen einer Fakultät einer nicht-negativen Ganzzahl oder zum Berechnen sowohl der nächsten Fakultät über einer nicht-negativen Ganzzahl als auch der ganzen Zahl, die diese Fakultät erzeugt.

In seinem Standardzustand v=1und tut es das letzteres durch Multiplikation vvon x(auch anfänglich 1) und Inkrementieren , xbis nzumindest so groß ist , dann kehrt sie vund x-1in einem Tupel.

Zur Berechnung n!einer Anrufe , h(n,0)die ein Vielfaches x(zunächst 1) durch nund dekrementiert , nbis nist , 0wenn er zurückkehrt x.

ibietet die lexikographische Index einer Permutation p, der Elemente , [0,1,...n]indem die Produkte der Fakultäts der Fakultäts Basis eines jeden Index nach oben, h(len(p)-j-1,0)und wie viele Elemente auf der rechten Seite des Index kleiner als der Wert in diesem Index sum(k<p[j]for k in p[j+1:]).


Ich denke, Sie müssen das letzte Element nicht in Sonderfällen angeben, wenn Sie die Permutation erstellen. Ich habe meine 255-Byte-GAP-Lösung nicht verwendet.
Christian Sievers

Ich füge es am Ende separat hinzu, da es sonst einen Fehler durch Null geben würde, wenn dies der Fall ist t/=x.
Jonathan Allan

Dauerte eine Weile , um zu sehen: die Schleife bereits tut alles, können Sie ersetzen (r+o)durch r.
Christian Sievers

Äh, du hast recht! Ich danke dir sehr.
Jonathan Allan

1

Python 2, 130 129 Bytes

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

Eigentlich , 18 11 Bytes

Diese Antwort verwendet den Algorithmus in Dennis 'Jelly-Antwort , ist aber 0-indiziert. Golfvorschläge willkommen! Probieren Sie es online!

4╞r;)╨E╨♂#í

Ungolfing

      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.
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.