Indice di permutazione inversa


17

introduzione

Le permutazioni lessicografiche di un elenco con n elementi possono essere numerate da 0 a n ! - 1. Ad esempio, il 3! = 6 permutazioni di (1,2,3)sarebbero (1,2,3), (1,3,2), (2,1,3), (2,3,1), (3,1,2), (3,2,1).

Quando una permutazione viene applicata a un elenco, i suoi elementi vengono ordinati nello stesso ordine dei numeri nella permutazione. Ad esempio, applicando la permutazione (2,3,1)ai l = (a,b,c)rendimenti (l[2],l[3],l[1]) = (b,c,a).

L'inverso di una permutazione è definito come la permutazione che inverte questa operazione, ovvero l'applicazione di una permutazione e quindi il suo inverso (o viceversa) non modifica l'array. Ad esempio, l'inverso di (2,3,1)è (3,1,2), poiché applicandolo ai (b,c,a)rendimenti (a,b,c).

Inoltre, l'inverso di una permutazione applicata alla permutazione stessa produce gli interi 1 ... n . Ad esempio, applicando (3,1,2)ai (2,3,1)rendimenti (1,2,3).

Definiamo ora la funzione revind ( x ) come indice della permutazione inversa della permutazione con indice x . (Questo è A056019 , se sei interessato.)

Poiché una permutazione con indice i modifica solo gli ultimi k elementi dell'elenco iff 0 ≤ i < k !, possiamo aggiungere un numero qualsiasi di elementi all'inizio dell'elenco senza influenzare revind ( i ). Pertanto la lunghezza dell'elenco non influisce sul risultato.

Sfida

Il tuo compito è implementare revind ( x ). Scriverai un programma o una funzione completa che accetta un singolo intero non negativo x come input / argomento e restituisce / restituisce il risultato come un singolo numero intero non negativo.

L'input e l'output possono essere 0-index o 1-index, ma questo deve essere coerente tra loro.

I builtin che generano permutazioni per indice, restituiscono l'indice di una permutazione o trovano la permutazione inversa sono vietati. (Sono consentiti i builtin che generano tutte le permutazioni o la permutazione successiva.)

Si applicano le regole standard del .

Esempi

Gli esempi seguenti sono indicizzati 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

Implementazione di riferimento (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
Ho dovuto cercare la definizione di permutazione inversa per comprendere questa sfida. Trovo il tuo esempio (a,b,c)estremamente chiaro. Si prega di includere una spiegazione corretta di cosa sia una permutazione inversa.
Fatalizza l'

@Fatalize Questo è un po 'difficile da spiegare semplicemente. Meglio ora?
PurkkaKoodari,

Jelly ha l'atomo (grado superiore) che ordina gli indici di un array in base ai loro valori corrispondenti. Questo accade a invertire una permutazione di 1, ..., n , ma non funziona per altri permutazioni. È vietato un built-in?
Dennis,

@Dennis Domanda difficile. Tecnicamente, trova l'inverso di qualsiasi permutazione dopo che è stata applicata a qualsiasi elenco strettamente crescente. Pertanto ho intenzione di dire non consentito. (Se qualcuno non è assolutamente d'accordo, sentiti libero di commentare. Potrei cambiare questo se la comunità lo desidera.)
PurkkaKoodari,

Risposte:


5

Gelatina , 6 byte

ịŒ!⁺iR

L'I / O utilizza l'indicizzazione basata su 1. Molto lento e affamato di memoria.

Verifica

Finché l'ingresso non supera 8! = 40320 , è sufficiente considerare tutte le permutazioni dell'array [1,…, 8] . Per l'ultimo caso di test, le permutazioni di [1,…, 9] sono sufficienti.

Con un codice leggermente modificato che considera solo le permutazioni dei primi 8 o 9 numeri interi positivi, puoi provarlo online! o verifica tutti i casi di test rimanenti .

Come funziona

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

Approccio alternativo, 6 byte (non valido)

Œ!Ụ€Ụi

È altrettanto lungo e usa l' atomo di grado superiore proibito , ma è (probabilmente) più idiomatico.

Anticipando 8 (o 9 per l'ultimo caso di test), possiamo effettivamente provarlo online!

Come funziona

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

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

Utilizza 1-indicizzazione. Molto inefficiente. (utilizza ~ 11 GB di memoria quando l'ingresso è 11)

Spiegazione

j=Range@#

Genera un elenco da 1 a N. Memorizza quello in j.

i=Permutations[...]

Trova tutte le permutazioni di j. Conservalo in i.

k=Position

Memorizza la Positionfunzione in k. (per ridurre il conteggio dei byte quando si utilizza di Positionnuovo)

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

Trova la permutazione inversa dell'N-esima permutazione.

Max@k[i,...]

Trova il k( Position) della permutazione inversa in i(tutte le permutazioni)

Utilizzo di built-in, 46 43 byte

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

1-indicizzati.


2
"I builtin che ... trovano la permutazione inversa sono vietati"
Greg Martin,

@GregMartin, ah, in qualche modo ho perso quella parte e ho visto solo la parte "restituisci l'indice di una permutazione". Silly me ... Il nuovo codice non ha questo problema.
JungHwan Min,

sì, sono d'accordo che è stato facile perdere. 74 byte, ancora piuttosto impressionante!
Greg Martin,

5

MATL , 15 byte

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

Input e output sono basati su 1.

Simile alla risposta CJam di @ MartinEnder , ma trova la permutazione inversa componendo tutte le possibili permutazioni con quella specificata dall'input e vedendo quale è diventata la permutazione dell'identità.

Si esaurisce la memoria nel compilatore online per l'input 10.

Provalo online!

Spiegazione

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

xJ.phQxL@JQh

Suite di test

0 indicizzato.

Spiegazione:

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 byte

Molto memoria inefficiente. Ora ancora più memoria inefficiente (ma 1 byte più breve).
Intervallo basato su 0.
Utilizza la codifica CP-1252 .

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

Provalo online! o come suite di test modificata

Spiegazione

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

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

Gli indici sono basati su 0.

Provalo online!

Non divento molto più inefficiente di così ... esaurisce la memoria con le impostazioni predefinite di Java per input maggiori di 8(ma funziona in linea di principio per input arbitrari dato un numero sufficiente di universi di tempo e memoria).

Spiegazione

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 byte

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

1-indicizzati. Newline non conteggiate, non sono necessarie. Non devo assegnare la funzione finale a un nome, ma ...

hè una funzione curry che prende un elenco di permutazioni e un indice in quell'elenco e restituisce l'indice della permutazione inversa. Senza restrizioni, lo farei semplicemente Position(l,l[n]^-1). fchiama quella funzione con le permutazioni ordinate di un gruppo abbastanza grande simmetrico e il dato n.

Potrei semplicemente scrivere SymmetricGroup(n), quindi la funzione potrebbe essere calcolata per valori fino a 9. Dato che ci sono già soluzioni molto più piccole, preferisco essere in grado di farlo:

gap> f(100001);
303017

Una soluzione veramente indicizzata 0 che funziona con argomenti inferiori a 99! (e può essere fatto funzionare per argomenti inferiori a 999! al costo di un byte) è questo:

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;

Dopo aver eliminato gli spazi bianchi, questo ha 255 byte.


Bel lavoro! Speravo di ottenere anche alcune soluzioni efficienti.
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-indicizzati. Funziona convertendo l'indice in una permutazione, invertendolo, quindi riconvertendolo in un indice. Modifica: risparmiato circa il 25% facendo finvertire e invertire la permutazione, quindi griconvertire la permutazione invertita in un indice. Ulteriori 10 byte salvati combinando le due chiamate ricorsive in un'unica funzione. 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 Spiacente, ho pensato di aver individuato un salvataggio dell'ultimo secondo a 9 byte ma non sono riuscito a testarlo a fondo. Sono tornato alla mia versione precedente.
Neil,

Implementazione molto rapida ora.
Jonathan Allan,

1
@JonathanAllan Risulta essere ancora più frettoloso se riesco fa invertire la permutazione invece di g...
Neil,

3

J, 55 50 byte

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

Basato sul saggio J sull'indice di permutazione .

Questo codice richiede solo memoria nell'ordine di nma utilizza più tempo poiché ordina i ntempi dell'elenco e li cerca nper ciascun indice.

Utilizzando l'integrato /:che è in grado di trovare il grado di un elenco e l'inverso di una permutazione, esiste una soluzione a 42 byte più efficiente.

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

Questa versione richiede solo 44 secondi per calcolare l'ultimo caso di test rispetto all'altra che richiede 105 secondi.

uso

   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 per l'efficienza della memoria che le lingue del golf non possono toccare.
Magic Octopus Urn,

2

Gelatina , 14 13 9 byte

-4 byte grazie a @Dennis (che ha continuato a giocare a golf usando il rapido nella sua risposta )

Œ!ịịŒ!$iR

Un'altra implementazione molto lenta.
Indicizzazione basata su 1 utilizzata qui, quindi i risultati attesi sono:

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

Non ha senso nemmeno mettere un link IDE online, poiché TIO uccide a un input di 10. Risultati locali (l'ultimo è molto lento e richiede una tonnellata di memoria!):

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

Come?

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

Nota: non è necessario ordinare le permutazioni poiché stiamo usando lo stesso ordinamento sia per trovare la permutazione sia per il suo inverso.


Non riesco a provarlo dal mio telefono, ma non riesci a sbarazzarti del link 2 e creare quello principale ÇịịÇ$iR?
Dennis,

In realtà, il Rprima Œ!è implicito, quindi Œ!ịịŒ!$iRdovrebbe fare il lavoro.
Dennis,

Sì, questa era un'entrata molto affrettata prima di incontrare gli amici.
Jonathan Allan,

2

Python 2, 116 114 byte

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-based. Lento e affamato di memoria ma a corto di byte.


Utilizzo di nessuna funzione di permutazione; sia memoria che tempo efficiente. 289 285 byte

-4 byte grazie a @Christian Sievers (piena permutazione già formata)

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

So che è il golf del codice ma penso che @ Pietu1998 sia interessato anche a implementazioni efficienti.

Guardalo in azione su repl.it

Mentre questo utilizza più byte rispetto all'implementazione di riferimento confrontando per n=5000000:

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

f è la funzione di indice inverso.

fprima ottiene il successivo fattoriale sopra n, te l'intero il cui fattoriale che è, xchiamando h(n)e imposta g=range(x), gli elementi che costituiranno la permutazione,o=g[:] e il titolare della permutazione,r=[]

Successivo costruisce la permutazione all'indice ndai poping indici della rappresentazione di base fattoriale na sua volta dagli elementi, oe aggiungendole a r. La rappresentazione di base fattoriale è trovato da div e mod di ncon tcui tè div'd da xe xdecrementa fino a 1.

Infine trova l'indice della permutazione inversa chiamando icon la permutazione inversa,[r.index(v)for v in g]

h è una funzione a doppio scopo per calcolare un fattoriale di un numero intero non negativo o per calcolare sia il fattoriale successivo sopra un numero intero non negativo sia il numero intero che lo rende fattoriale.

Nel suo stato di default v=1e lo fa la seconda moltiplicando vper x(anche inizialmente 1) e di incrementare xfino nè almeno altrettanto grande, poi ritorna vex-1 in una tupla.

Per calcolare n!una chiamate h(n,0)che multipli x(inizialmente 1) da ne decrementi nfino nè 0quando ritornax .

ifornisce l'indice lessicografico di una permutazione, p, degli elementi [0,1,...n]sommando i prodotti del fattoriale della base fattoriale di ciascun indice, h(len(p)-j-1,0)e il numero di elementi a destra dell'indice sono inferiori al valore a tale indice, sum(k<p[j]for k in p[j+1:]).


Penso che non sia necessario caso speciale l'ultimo elemento quando si costruisce la permutazione. Non l'ho fatto nella mia soluzione GAP a 255 byte.
Christian Sievers,

Lo aggiungo separatamente alla fine perché altrimenti ci sarebbe una divisione per errore zero quando lo fa t/=x.
Jonathan Allan,

Mi ci è voluto un po 'per vedere: il loop fa già tutto, puoi sostituirlo (r+o)con r.
Christian Sievers,

Hai ragione! Grazie mille.
Jonathan Allan,

1

Python 2, 130 129 byte

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

In realtà , 18 11 byte

Questa risposta utilizza l'algoritmo nella risposta Jelly di Dennis ma è indicizzata a 0. Suggerimenti di golf benvenuti! Provalo 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.
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.