Classificação de inserção reversa

19

Objetivo

Gere a lista codificada original, a partir dos movimentos que uma Classificação de inserção faria para classificá-la. A lista original terá todos os números de 0até N-1(inclusive) onde Nestá o tamanho da entrada.

Entrada

Uma lista contendo as movimentações necessárias para classificar a lista. Cada valor representa a quantidade de slots deslocados pelo número original (codificado) para estar na posição correta, lembre-se de que esse processo é da esquerda para a direita.
O valor na posição (indexada 0) ina lista de entrada estará entre 0e iinclusive.
Você não precisa lidar com entradas inválidas; nesse caso, qualquer comportamento é aceitável (falha, loop infinito, etc.).

Resultado

A lista embaralhada

Passo a passo para gerar os movimentos

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]

Portanto, para a entrada que [0,1,1,2,1,0]seu programa precisa produzir [4,0,2,1,3,5].
Lembre-se de que os movimentos não estão na posição na lista classificada (final), mas no segmento classificado (a seção em negrito)

Casos de teste

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

Ganhando

Isso é , então a resposta mais curta vence.

Cajado
fonte
11
O programa também pode incluir o comprimento da lista como entrada?
Mbomb007
@ mbomb007 não.
Rod
Podemos usar as etapas (n-1)? O primeiro é desnecessário, pois é sempre zero.
GB
@GB certeza, desde a saída é certa, você pode usar qualquer algoritmo
Rod

Respostas:

14

Gelatina , 12 bytes

L!_UÆ¡$œ?J’U

Experimente online!

Explicação

Podemos basicamente ver as duas listas (a entrada e a saída) como codificando um número inteiro; a entrada codifica um número inteiro na base fatorial e a saída codifica um número inteiro como uma permutação. Felizmente, o Jelly tem embutidos que já estão muito próximos dessas duas codificações, portanto, basta escrever pequenos pedaços de código para converter em um número inteiro e depois voltar para a outra codificação.

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

No caso do fatorial de base, podemos observar que o primeiro elemento da lista deve ser 0, o segundo pode ser 0 ou 1, o terceiro deve ser 0/1/2 e assim por diante. Portanto, temos que reverter a entrada para obter seus elementos na ordem de escrita normal para conversão de base.

Além disso, para que as ordens relativas da conversão fatorial e da conversão de permutação correspondam à operação usada pela classificação por inserção, precisamos fazer dois ajustes: reverter a sequência das permutações e reverter a ordem da lista de saída. Inverter a lista de saída é bastante fácil, necessitando apenas de umU no final do programa. Para reverter a sequência de permutações, subtraímos o fatorial do comprimento de entrada (isso funciona porque o fatorial base produz um número no intervalo de 0 a (comprimento! -1), enquanto as permutações são numeradas pela geléia de 1 a comprimento! , produzindo um off-by-one implícito que cancela o off-one que você normalmente obtém ao subtrair um índice de permutação de um fatorial).

Jelly , 9 bytes, em colaboração com @JonathanAllan

UÆ¡Nœ?J’U

Esta versão do programa é muito semelhante, mas usa um método diferente de reverter a sequência de permutações; simplesmente negar a entrada com Né suficiente para œ?tratar a ordem ao contrário. Além disso, funciona de forma idêntica ao programa anterior.

Experimente online!


fonte
4
O_O Que feitiçaria é essa?
21917 DLosc
Oh, legal - eu sabia que meus átomos Æ¡e œ?trabalhariam para isso (eu já havia começado a tentar usá-los para esse desafio mais cedo - eu estava tão perto, só precisava do L!lá).
Jonathan Allan
Código excelente!
Greg Martin
11
De fato, você pode fazer isso em 9 bytes UÆ¡Nœ?L’Uporque eu implementei œ?(e similares) para agir de forma modular (como se eles estivessem usando listas de geléia). O Njusto indexa com o valor negativo. Nota: Eu mudei Jpara L- isso ocorre porque, dado um número, ele faz um intervalo oculto).
Jonathan Allan
6

Mathematica, 92 bytes

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

Função pura, recebendo uma lista de números inteiros não negativos como entrada e retornando uma lista de números inteiros não negativos. O código acima contém a ©, que está incorreto: é um espaço reservado para o símbolo de 3 bytes U + F3DE, que o Mathematica representa por um círculo com um ponto e representa a composição das permutações.

c=Cycles@{#}&define uma função que converte uma lista de números inteiros em um Cyclesobjeto que representa uma permutação; por exemplo, c[{3,4}]são os elementos de troca de transposição 3 e 4 de uma lista. c[i-0~Range~#[[i]]]~Table~{i,l,1,-1}]pega a lista de entrada e gera as permutações necessárias para desfazer a classificação de inserção. Em seguida, c@{}©##&@@compõe todas essas permutações juntas, começando pela permutação de identidade c@{}. Por fim, Permute[Range[l=Length@#]-1,...]aplica essa permutação à lista indexada em 0 de comprimento apropriado.

Greg Martin
fonte
11
O que não embutido ?! Certamente ...
Jonathan Allan
3
@{#}&)@{}©##&@@Parece assustador.
Yytsi
6

Python 2, 79 68 bytes

Agradecimentos a Krazor por salvar 10 bytes

Obrigado a TuukkaX por economizar 1 byte

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

Funciona gerando os movimentos em sentido inverso

viciado em matemática
fonte
2
Faça esse 66 ! Como sobre: a=input();b=range(len(a));print[b.pop(j-a[j]) for j in b[::-1]][::-1]. Lista compreensões ftw!
FMaz
11
@Krazor Você tem um espaço que poderia ser removido antes for, por isso verifique que 65 eu acho: D
Yytsi
@Krazor Acontece que a compreensão da lista não funcionou muito bem, mas gostei da ideia de usar b [:: - 1]!
matemática viciado em
De jeito nenhum? Comentei com o celular, talvez tenha digitado algo errado. Qual parte não funciona? Para mim, ele interpretou corretamente e atendeu a todos os casos de teste.
FMaz 18/02/19
@ Krazor Oh, opa, não, você está certo. Fui eu quem digitou errado durante o teste.
math junkie
5

JavaScript (ES6), 69 65 63 bytes

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

Irritantemente, tanto a entrada quanto a saída estão na ordem errada. Editar: salvou 4 bytes graças a @Arnauld. Economizou 2 bytes graças a @ETHproductions.

Neil
fonte
Eu ainda estava tentando encontrar uma maneira melhor, mas você foi muito mais rápido. Agradável!
Arnauld
11
Você não precisa i, não é?
Arnauld
@ Arnauld Aparentemente não. Comecei tentando entender a resposta do Python, e acabei de perceber que ele não usa i...
Neil
11
Fácil -2:o=>+b.splice(~o,1)
ETHproductions
3

JavaScript (ES6), 73 71 bytes

Economizou 2 bytes graças a ETHproductions

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

Casos de teste

Arnauld
fonte
Ótima maneira de obter o comprimento e o alcance ao mesmo tempo. Eu ia sugerir a=m.map(_=>j++,j=0), mas esse é o mesmo comprimento e tenho certeza que você já tentou.
ETHproductions
@ETHproductions Você está certo: eu também tentei. :-) (Pode ser interessante notar que este não é equivalente: isto iria definir ja a.lengthvez de a.length-1e exigiria a.splice(--j,0,a.splice(j-m[j],1)[0]))
Arnauld
Heh, eu pensei nisso também, mas eu não acho que foi pena mencionar porque é o mesmo comprimento
ETHproductions
11
Fácil -2:+a.splice(j-m[j--],1)
ETHproductions
2

Haskell , 85 bytes

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

Experimente online! Exemplo de uso: f [0,1,1,2,1,0]rendimentos [4,0,2,1,3,5].

f xchama a função #com a lista xinvertida e uma lista [length x - 1, length x - 2, ... , 0]. (n:r)#lexecuta a classificação de inserção reversa retirando recursivamente o nth elemento l, em que l!!nproduz o nth elemento e take n l++drop(n+1)la lista lcom o nth elemento removido.

Laikoni
fonte
Haskell, tão bonito.
FMaz
1

perl, 61 bytes

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

A saída termina na matriz @o. Exemplo com matriz de entrada como argumentos de linha de comando:

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.
fonte
1

Ruby, 49 bytes

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

Executa a "inserção reversa" no lugar dentro da lista, começando com o maior número.

GB
fonte