Indice de permutation inverse

17

introduction

Les permutations lexicographiques d'une liste à n éléments peuvent être numérotées de 0 à n ! - 1. Par exemple, le 3! = 6 permutations (1,2,3)seraient (1,2,3), (1,3,2), (2,1,3), (2,3,1), (3,1,2), (3,2,1).

Lorsqu'une permutation est appliquée à une liste, ses éléments sont ordonnés dans le même ordre que les nombres dans la permutation. Par exemple, appliquer la permutation (2,3,1)aux l = (a,b,c)rendements (l[2],l[3],l[1]) = (b,c,a).

L'inverse d'une permutation est défini comme la permutation qui inverse cette opération, c'est-à-dire que l'application d'une permutation et que son inverse (ou vice versa) ne modifie pas le tableau. Par exemple, l'inverse de (2,3,1)est (3,1,2), car cela s'applique aux (b,c,a)rendements (a,b,c).

De plus, l'inverse d'une permutation appliquée à la permutation elle-même donne les entiers 1… n . Par exemple, appliquer (3,1,2)aux (2,3,1)rendements (1,2,3).

Nous définissons maintenant la fonction revind ( x ) comme l'indice de la permutation inverse de la permutation d'indice x . (Ceci est A056019 , si vous êtes intéressé.)

Puisqu'une permutation d'indice i ne modifie que les k derniers éléments de la liste si sf 0 ≤ i < k !, Nous pouvons ajouter un nombre quelconque d'éléments au début de la liste sans affecter revind ( i ). Par conséquent, la longueur de la liste n'affecte pas le résultat.

Défi

Votre tâche consiste à implémenter revind ( x ). Vous écrirez un programme ou une fonction complète qui prend un seul entier non négatif x comme entrée / argument et génère / renvoie le résultat comme un seul entier non négatif.

L'entrée et la sortie peuvent être indexées 0 ou indexées 1, mais cela doit être cohérent entre elles.

Les builtins qui génèrent des permutations par index, renvoient l'index d'une permutation ou trouvent la permutation inverse sont interdits. (Les Builtins qui génèrent toutes les permutations ou la permutation suivante sont autorisés.)

Les règles de standard s'appliquent.

Exemples

Les exemples ci-dessous sont indexés 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

Implémentation de référence (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]
PurkkaKoodari
la source
1
J'ai dû chercher la définition de la permutation inverse pour comprendre ce défi. Je trouve votre exemple (a,b,c)extrêmement peu clair. Veuillez inclure une explication appropriée de ce qu'est une permutation inverse.
Fatalize
@Fatalize C'est un peu difficile à expliquer simplement. Mieux maintenant?
PurkkaKoodari
Jelly a l'atome (grade up) qui trie les indices d'un tableau par leurs valeurs correspondantes. Cela se produit pour inverser une permutation de 1,…, n , mais cela ne fonctionne pas pour les autres permutations. Un intégré est-il interdit?
Dennis
@Dennis Question difficile. Techniquement, il trouve l'inverse de toute permutation après avoir été appliquée à une liste strictement croissante. Je vais donc dire non autorisé. (Si quelqu'un est strictement en désaccord, n'hésitez pas à commenter. Je peux changer cela si la communauté le souhaite.)
PurkkaKoodari

Réponses:

5

Gelée , 6 octets

ịŒ!⁺iR

Les E / S utilisent une indexation basée sur 1. Très lent et gourmand en mémoire.

Vérification

Tant que l'entrée ne dépasse pas 8! = 40320 , il suffit de considérer toutes les permutations du tableau [1,…, 8] . Pour le dernier cas de test, les permutations de [1,…, 9] suffisent.

Avec un code légèrement modifié qui ne prend en compte que les permutations des 8 ou 9 premiers entiers positifs, vous pouvez l' essayer en ligne! ou vérifiez tous les cas de test restants .

Comment ça fonctionne

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

Approche alternative, 6 octets (invalide)

Œ!Ụ€Ụi

Il est tout aussi long et utilise l' atome de qualité interdit , mais il est (sans doute) plus idiomatique.

En ajoutant 8 (ou 9 pour le dernier cas de test), nous pouvons réellement l' essayer en ligne!

Comment ça fonctionne

Œ!Ụ€Ụ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.
Dennis
la source
6

Mathematica, 74 octets

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

Utilise l'indexation 1. Très inefficace. (utilise ~ 11 Go de mémoire lorsque l'entrée est 11)

Explication

j=Range@#

Générez une liste de 1 à N. Enregistrez-la dans j.

i=Permutations[...]

Trouvez toutes les permutations de j. Conservez-le dans i.

k=Position

Enregistrez la Positionfonction dans k. (pour réduire le nombre d'octets lors d'une Positionnouvelle utilisation )

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

Trouvez la permutation inverse de la N-ème permutation.

Max@k[i,...]

Trouvez le k( Position) de la permutation inverse dans i(toutes les permutations)

À l'aide de intégrés, 46 43 octets

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

1 indexé.

JungHwan Min
la source
2
"Les constructions qui ... trouvent la permutation inverse sont interdites"
Greg Martin
@GregMartin, ah, j'ai en quelque sorte raté cette partie et je n'ai vu que la partie "renvoyer l'index d'une permutation". Idiot moi ... Le nouveau code n'a pas ce problème.
JungHwan Min
oui, je suis d'accord que c'était facile à manquer. 74 octets - toujours assez impressionnant!
Greg Martin
5

MATL , 15 octets

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

L'entrée et la sortie sont basées sur 1.

Similaire à la réponse CJam de @ MartinEnder , mais trouve la permutation inverse en composant toutes les permutations possibles avec celle spécifiée par l'entrée, et en voyant qui est devenue la permutation d'identité.

Il manque de mémoire dans le compilateur en ligne pour l'entrée 10.

Essayez-le en ligne!

Explication

:      % 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
Luis Mendo
la source
5

Pyth, 12 octets

xJ.phQxL@JQh

Suite de tests

0 indexé.

Explication:

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.
isaacg
la source
5

05AB1E , 14 13 octets

Mémoire très inefficace. Désormais encore plus de mémoire inefficace (mais 1 octet plus court).
Plage basée sur 0.
Utilise l' encodage CP-1252 .

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

Essayez-le en ligne! ou en tant que suite de tests modifiée

Explication

ƒ               # 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
Emigna
la source
4

CJam , 16 octets

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

Les indices sont basés sur 0.

Essayez-le en ligne!

Je n'obtiens pas beaucoup plus inefficace que cela ... manque de mémoire avec les paramètres par défaut de Java pour les entrées supérieures à 8(mais fonctionne en principe pour les entrées arbitraires étant donné un nombre suffisant d'univers de temps et de mémoire).

Explication

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.
Martin Ender
la source
3

GAP , 108 octets

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

1 indexé. Les sauts de ligne ne sont pas comptés, ils ne sont pas nécessaires. Je n'ai pas vraiment besoin d'assigner la fonction finale à un nom, mais ...

hest une fonction curry prenant une liste de permutations et un index dans cette liste et retournant l'indice de permutation inverse. Sans restrictions, je ferais juste Position(l,l[n]^-1). fappelle cette fonction avec les permutations triées d'un groupe symétrique suffisamment grand et le donné n.

Je pourrais simplement écrire SymmetricGroup(n), puis la fonction pourrait être calculée pour des valeurs allant jusqu'à 9. Puisqu'il existe déjà des solutions beaucoup plus petites, je préfère pouvoir faire ceci:

gap> f(100001);
303017

Une solution indexée 0 vraiment efficace qui fonctionne pour des arguments inférieurs à 99! (et peut fonctionner pour des arguments inférieurs à 999! au prix d'un octet) est celui-ci:

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;

Après avoir supprimé les espaces, cela a 255 octets.

Christian Sievers
la source
Bon travail! J'espérais aussi trouver des solutions efficaces.
PurkkaKoodari
3

JavaScript (ES6), 163 120 110 octets

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 indexé. Fonctionne en convertissant l'index en permutation, en l'inversant, puis en reconvertissant en index. Edit: économisé environ 25% en finversant et inversant la permutation, puis en gconvertissant la permutation inversée en index. 10 octets supplémentaires enregistrés en combinant les deux appels récursifs en une seule fonction. Non golfé:

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;
}
Neil
la source
1
@JonathanAllan Désolé, je pensais avoir repéré une sauvegarde de 9 octets de dernière seconde, mais je n'ai pas pu le tester à fond. Je suis revenu à ma version précédente.
Neil
Mise en œuvre très rapide maintenant.
Jonathan Allan
1
@JonathanAllan se révèle encore plus bruyant si j'arrive fà inverser la permutation au lieu de g...
Neil
3

J, 55 50 octets

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

Basé sur l'essai J sur l' indice de permutation .

Ce code ne nécessite que de la mémoire de l'ordre de nmais utilise plus de temps car il trie les ntemps de liste et recherche les ntemps pour chaque index.

En utilisant la fonction intégrée /:qui est capable de trouver le grade d'une liste et l'inverse d'une permutation, il existe une solution de 42 octets plus efficace.

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

Cette version ne nécessite que 44 secondes pour calculer le dernier cas de test par rapport à l'autre qui nécessite 105 secondes.

Usage

   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
miles
la source
+1 pour une efficacité mémoire que les langues de golf ne peuvent pas toucher.
Urne de poulpe magique du
2

Gelée , 14 13 9 octets

-4 octets grâce à @Dennis (qu'il a joué plus loin en utilisant le rapide dans sa réponse )

Œ!ịịŒ!$iR

Une autre implémentation très lente.
L'indexation basée sur 1 est utilisée ici, donc les résultats attendus sont:

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

Inutile même de mettre en place un lien IDE en ligne, car TIO tue à une entrée de 10. Résultats locaux (le dernier est très lent et a nécessité une tonne de mémoire!):

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

Comment?

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

Remarque: pas besoin de trier les permutations car nous utilisons le même ordre pour trouver la permutation et l'inverse.

Jonathan Allan
la source
Vous ne pouvez pas le tester depuis mon téléphone, mais ne pouvez-vous pas vous débarrasser du lien 2 et en créer le principal ÇịịÇ$iR?
Dennis
En fait, l' Ravant Œ!est implicite, donc Œ!ịịŒ!$iRdevrait faire le travail.
Dennis
Oui, c'était une entrée très précipitée avant de rencontrer des amis.
Jonathan Allan
2

Python 2, 116 114 octets

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

Basé sur 0. Lent et faim de mémoire mais peu d'octets.


Utiliser aucune fonction de permutation; à la fois mémoire et temps. 289 285 octets

-4 octets grâce à @Christian Sievers (permutation complète déjà formée)

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

Je sais que c'est du golf de code, mais je pense que @ Pietu1998 est également intéressé par des implémentations efficaces.

Voyez-le en action sur repl.it

Bien que cela utilise plus d'octets que l'implémentation de référence pour n=5000000:

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

f est la fonction d'index inverse.

fobtient d'abord la factorielle suivante ci n- dessus , tet l'entier dont la factorielle qui est, xen appelant h(n), et définit g=range(x), les éléments qui constitueront la permutation o=g[:], et le titulaire de la permutation,r=[]

Ensuite, il construit la permutation à l'indice nen poping les indices de la représentation de base factorielle nà tour de rôle à partir des éléments,o , et en les ajoutant à r. La représentation de base factoriel se trouve par div et mod de navec ttest div'd par xet xdécrémente jusqu'à 1.

Enfin, il trouve l'indice de la permutation inverse en appelant iavec la permutation inverse,[r.index(v)for v in g]

h est une fonction à double usage pour calculer une factorielle d'un entier non négatif ou pour calculer à la fois la factorielle suivante au-dessus d'un entier non négatif et l'entier qui rend cette factorielle.

Dans son état par défaut v=1et il le fait en multipliant vpar x(également initialement1 ) et en incrémentant xjusqu'à ce qu'il nsoit au moins aussi grand, puis il revient vet x-1dans un tuple.

Pour calculer n!un appel h(n,0)qui multiplie x(initialement 1) par net décroît njusqu'àn est 0quand il retourne x.

ifournit l'indice lexicographique d'une permutation, p, des éléments [0,1,...n]en additionnant les produits de la factoriel de la base factoriel de chaque indice, h(len(p)-j-1,0)et le nombre d' éléments à droite de l'indice est inférieur à la valeur à cet indice, sum(k<p[j]for k in p[j+1:]).

Jonathan Allan
la source
Je pense que vous n'avez pas besoin de caser le dernier élément lors de la construction de la permutation. Je ne l'ai pas dans ma solution GAP de 255 octets.
Christian Sievers
Je l'ajoute séparément à la fin car sinon il y aurait une erreur de division par zéro quand cela se produirait t/=x.
Jonathan Allan
Il m'a fallu un certain temps pour voir: la boucle fait déjà tout, vous pouvez la remplacer (r+o)par r.
Christian Sievers
Euh, tu as raison! Merci beaucoup.
Jonathan Allan
1

Python 2, 130 129 octets

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
Dennis
la source
1

En fait , 18 11 octets

Cette réponse utilise l'algorithme de la réponse Jelly de Dennis mais est indexée sur 0. Suggestions de golf bienvenues! Essayez-le en ligne!

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.
Sherlock9
la source