Tri par insertion inverse

19

Objectif

Générez la liste brouillée d'origine, à partir des mouvements qu'un tri d'insertion ferait pour le trier. La liste d'origine aura tous les nombres de 0à N-1(inclus) où Nest la taille de l'entrée.

Contribution

Une liste contenant les mouvements nécessaires pour trier la liste. Chaque valeur représente le nombre d'emplacements déplacés par le numéro d'origine (brouillé) pour se trouver dans sa bonne position, gardez à l'esprit que ce processus se déroule de gauche à droite.
La valeur à la position (indexée 0) idans la liste d'entrée sera comprise entre 0et iinclusive.
Vous n'avez pas besoin de gérer des entrées invalides, tout comportement est acceptable dans ce cas (crash, boucle infinie, etc.).

Production

La liste brouillée

Pas à pas pour générer les mouvements

Scrambled List | Moves to sort
[4,0,2,1,3,5]  | [0, , , , , ] #4 stay in place
[4,0,2,1,3,5]  | [0,1, , , , ] #0 is moved 1 slot to the left
[0,4,2,1,3,5]  | [0,1,1, , , ] #2 is moved 1 slot
[0,2,4,1,3,5]  | [0,1,1,2, , ] #1 is moved 2 slot
[0,1,2,4,3,5]  | [0,1,1,2,1, ] #3 is moved 1 slot
[0,1,2,3,4,5]  | [0,1,1,2,1,0] #5 is in the right place already
[0,1,2,3,4,5]

Donc, pour l'entrée que [0,1,1,2,1,0]votre programme doit produire [4,0,2,1,3,5].
Gardez à l'esprit que les mouvements ne sont pas à la position dans la liste triée (finale), mais dans le segment trié (la section en gras)

Cas de test

[0,0,0] -> [0,1,2]
[0,1,0,1] -> [1,0,3,2]
[0,0,0,0,0,5] -> [1,2,3,4,5,0]
[0,1,2,3] -> [3,2,1,0]
[0,1,1,1] -> [3,0,1,2]
[0,1,1,2,1,0] -> [4,0,2,1,3,5]

Gagnant

C'est le , donc la réponse la plus courte l'emporte.

Barre
la source
1
Le programme peut-il également prendre la longueur de la liste en entrée?
mbomb007
@ mbomb007 non.
Rod
Pouvons-nous utiliser des étapes (n-1) à la place? Le premier est inutile, car il est toujours nul.
GB
@GB bien sûr, tant que la sortie est correcte, vous pouvez utiliser n'importe quel algorithme
Rod

Réponses:

14

Gelée , 12 octets

L!_UÆ¡$œ?J’U

Essayez-le en ligne!

Explication

Nous pouvons essentiellement voir les deux listes (l'entrée et la sortie) comme encodant un entier; l'entrée code un entier en base factorielle et la sortie code un entier en permutation. Heureusement, Jelly a des intrinsèques qui sont déjà très proches de ces deux encodages, il s'agit donc simplement d'écrire de petits morceaux de code à convertir en un entier, puis de revenir à l'autre encodage.

L!_UÆ¡$œ?J’U
   U           Reverse {the input}
    Æ¡         and convert from base factorial to integer;
  _   $        subtract that from
L!             the factorial of the length of {the input};
       œ?      then take the nth permutation of
         J     [1,2,...,l], where l is the length of {the input},
          ’    subtract 1 from every elevent,
           U   and reverse it

Dans le cas de la factorielle de base, on peut observer que le premier élément de la liste doit être 0, le second peut être 0 ou 1, le troisième doit être 0/1/2, etc. Ainsi, nous devons inverser l'entrée afin de placer ses éléments dans l'ordre d'écriture normal pour la conversion de base.

De plus, pour que les ordres relatifs de la conversion factorielle et de la conversion de permutation correspondent à l'opération utilisée par le tri par insertion, nous devons effectuer deux ajustements: inverser la séquence des permutations et inverser l'ordre de la liste de sortie. Inverser la liste de sortie est assez facile, ne nécessitant qu'un Uà la fin du programme. Pour inverser la séquence des permutations, nous soustrayons de la factorielle de la longueur d'entrée (cela fonctionne parce que la factorielle de base produit un nombre compris entre 0 et (longueur! -1), tandis que les permutations sont numérotées par Jelly de 1 à la longueur! , produisant un off-by-one implicite qui annule le off-by-one que vous obtenez normalement en soustrayant un indice de permutation d'une factorielle).

Jelly , 9 octets, en collaboration avec @JonathanAllan

UÆ¡Nœ?J’U

Cette version du programme est très similaire, mais utilise une méthode différente pour inverser la séquence des permutations; il suffit de nier l'entrée avec Npour faire œ?traiter l'ordre à l'envers. En dehors de cela, il fonctionne de manière identique au programme précédent.

Essayez-le en ligne!


la source
4
O_O De quelle sorcellerie s'agit- il?
DLosc
Oh bien - je savais que mes atomes Æ¡et moi œ?fonctionneraient pour cela (j'avais déjà commencé à essayer de les utiliser pour ce défi plus tôt - j'étais si proche, j'avais juste besoin de ça L!).
Jonathan Allan
Excellent code!
Greg Martin
1
En fait, vous pouvez le faire en 9 octets avec UÆ¡Nœ?L’Uparce que j'ai implémenté œ?(et similaire) pour agir de manière modulaire (comme s'ils utilisaient des listes Jelly). Le Njuste indexe avec la valeur négative. Remarque: j'ai changé Jpour L- c'est simplement parce que, étant donné un certain nombre, cela fait une gamme sous le capot de toute façon).
Jonathan Allan
6

Mathematica, 92 octets

Permute[Range[l=Length@#]-1,(c=Cycles@{#}&)@{}©##&@@c[i-0~Range~#[[i]]]~Table~{i,l,1,-1}]&

Fonction pure prenant une liste d'entiers non négatifs en entrée et renvoyant une liste d'entiers non négatifs. Le code ci-dessus contient un ©, ce qui est incorrect: c'est un espace réservé pour le symbole à 3 octets U + F3DE, que Mathematica représente par un cercle avec un point dedans, et qui représente la composition des permutations.

c=Cycles@{#}&définit une fonction qui convertit une liste d'entiers en un Cyclesobjet représentant une permutation; par exemple, c[{3,4}]est la transposition des éléments d'échange 3 et 4 d'une liste. c[i-0~Range~#[[i]]]~Table~{i,l,1,-1}]prend la liste d'entrée et génère les permutations nécessaires pour annuler le tri par insertion. Ensuite, c@{}©##&@@compose toutes ces permutations ensemble, en commençant par la permutation d'identité c@{}. Enfin, Permute[Range[l=Length@#]-1,...]applique cette permutation à la liste indexée 0 de longueur appropriée.

Greg Martin
la source
1
Qu'est-ce pas intégré?! Sûrement ...
Jonathan Allan
3
@{#}&)@{}©##&@@est effrayant.
Yytsi
6

Python 2, 79 68 octets

Merci à Krazor pour avoir économisé 10 octets

Merci à TuukkaX pour avoir économisé 1 octet

a=input();b=range(len(a));print[b.pop(j-a[j])for j in b[::-1]][::-1]

Fonctionne en générant les mouvements à l'envers

accro aux mathématiques
la source
2
Faites ça 66 ! Que diriez - vous: a=input();b=range(len(a));print[b.pop(j-a[j]) for j in b[::-1]][::-1]. Liste des compréhensions ftw!
FMaz
1
@Krazor Vous avez un espace qui pourrait être supprimé auparavant for, alors faites-en 65 je suppose: D
Yytsi
@Krazor Il s'avère que la compréhension de la liste n'a pas tout à fait fonctionné, mais j'ai aimé l'idée d'utiliser b [:: - 1]!
math junkie
En aucune façon? J'ai commenté avec le mobile, j'ai peut-être mal écrit quelque chose. Quelle partie ne fonctionne pas? Pour moi, il a interprété correctement et rempli tous les cas de test.
FMaz
@Krazor Oh whoops, non vous avez raison. Je suis celui qui l'a mal tapé lors des tests.
math junkie
5

JavaScript (ES6), 69 65 63 octets

a=>a.reverse(b=[...a.keys()]).map(o=>+b.splice(~o,1)).reverse()

De manière ennuyeuse, l'entrée et la sortie sont dans le mauvais ordre. Edit: 4 octets enregistrés grâce à @Arnauld. Enregistré 2 octets grâce à @ETHproductions.

Neil
la source
J'essayais toujours de trouver un meilleur moyen mais tu étais beaucoup plus rapide. Joli!
Arnauld
1
Vous n'avez pas besoin i, n'est -ce pas?
Arnauld
@Arnauld Apparemment non. J'ai commencé par essayer de comprendre la réponse Python, et je viens juste de remarquer qu'elle n'utilise pas réellement i...
Neil
1
Easy -2:o=>+b.splice(~o,1)
ETHproductions
3

JavaScript (ES6), 73 71 octets

Sauvegardé 2 octets grâce à ETHproductions

m=>(a=m.map((_,i)=>j=i)).map(_=>a.splice(j,0,+a.splice(j-m[j--],1)))&&a

Cas de test

Arnauld
la source
Belle façon d'obtenir la longueur et la portée en même temps. J'allais suggérer a=m.map(_=>j++,j=0), mais c'est la même longueur et je suis sûr que vous l'avez déjà essayé.
ETHproductions
@ETHproductions Vous avez raison: je l'ai également essayé. :-) (Il est intéressant de noter que ce ne sont pas équivalentes: ce fixerait jà a.lengthplutôt que a.length-1et nécessiterait a.splice(--j,0,a.splice(j-m[j],1)[0]))
Arnauld
Hé, j'y ai pensé aussi, mais je ne pensais pas que ça valait la peine d'être mentionné parce que c'est la même longueur
ETHproductions
1
Easy -2:+a.splice(j-m[j--],1)
ETHproductions
2

Haskell , 85 octets

f x|n<-length x-1=reverse x#[n,n-1..0]
(n:r)#l=r#(take n l++drop(n+1)l)++[l!!n]
x#l=x

Essayez-le en ligne! Exemple d'utilisation: f [0,1,1,2,1,0]rendements [4,0,2,1,3,5].

f xappelle la fonction #avec liste xinversée et une liste [length x - 1, length x - 2, ... , 0]. (n:r)#leffectue le tri par insertion inverse en retirant récursivement le nth élément l, où l!!nrenvoie le nth élément et take n l++drop(n+1)lproduit la liste lavec le nth élément supprimé.

Laikoni
la source
Haskell, si belle.
FMaz
1

perl, 61 octets

@o=@p=0..@ARGV-1;splice@o,$_,0,splice@o,$_-pop,1for reverse@p

La sortie se retrouve dans le tableau @o. Exemple avec un tableau d'entrée comme arguments de ligne de commande:

perl -le'@o=@p=0..@ARGV-1;splice@o,$_,0,splice@o,$_-pop,1for reverse@p;print@o' 0 1 1 2 1 0
402135
Kjetil S.
la source
1

Rubis, 49 octets

->l{(w=l.size).times{l.insert(l.shift+w-=1,w)};l}

Effectue «l'insertion inverse» en place dans la liste, en commençant par le plus grand nombre.

GB
la source