Separar uma matriz


44

Desafio

Dada uma matriz não vazia de números inteiros, por exemplo:

[5, 2, 7, 6, 4, 1, 3]

Primeiro, divida-o em matrizes onde nenhum item é maior que o anterior (ou seja, matrizes não ascendentes):

[5, 2] [7, 6, 4, 1] [3]

Em seguida, inverta cada matriz:

[2, 5] [1, 4, 6, 7] [3]

Por fim, concatene-os todos juntos:

[2, 5, 1, 4, 6, 7, 3]

Isso deve ser o que o programa sai / função retorna. Repita esse procedimento várias vezes e a matriz será totalmente classificada.

Regras

  • A entrada e a saída podem ser fornecidas por qualquer método padrão e podem estar em qualquer formato razoável de matriz.
  • A matriz de entrada nunca estará vazia, mas pode conter negativos e / ou duplicatas.
  • O valor absoluto de cada número inteiro sempre será menor que 2 31 .

Casos de teste

Esperemos que estes abranjam todos os casos extremos:

[1] -> [1]
[1, 1] -> [1, 1]
[1, 2] -> [1, 2]
[2, 1] -> [1, 2]
[2, 3, 1] -> [2, 1, 3]
[2, 1, 3] -> [1, 2, 3]
[2, 1, 2] -> [1, 2, 2]
[2, 1, 1] -> [1, 1, 2]
[3, 1, 1, 2] -> [1, 1, 3, 2]
[3, 2, 1, 2] -> [1, 2, 3, 2]
[3, 1, 2, 2] -> [1, 3, 2, 2]
[1, 3, 2, 2] -> [1, 2, 2, 3]
[1, 0, 5, -234] -> [0, 1, -234, 5]
[1, 0, 1, 0, 1] -> [0, 1, 0, 1, 1]
[1, 2, 3, 4, 5] -> [1, 2, 3, 4, 5]
[5, 4, 3, 2, 1] -> [1, 2, 3, 4, 5]
[2, 1, 5, 4, 3] -> [1, 2, 3, 4, 5]
[2, 3, 1, 5, 4] -> [2, 1, 3, 4, 5]
[5, 1, 4, 2, 3] -> [1, 5, 2, 4, 3]
[5, 2, 7, 6, 4, 1, 3] -> [2, 5, 1, 4, 6, 7, 3]
[-5, -2, -7, -6, -4, -1, -3] -> [-5, -7, -2, -6, -4, -3, -1]
[14, 5, 3, 8, 15, 7, 4, 19, 12, 0, 2, 18, 6, 11, 13, 1, 17, 16, 10, 9] -> [3, 5, 14, 8, 4, 7, 15, 0, 12, 19, 2, 6, 18, 11, 1, 13, 9, 10, 16, 17]

Pontuação

Isso é , então o código mais curto em bytes vence.


4
Qual é a vantagem desse método de classificação?
mbomb007

1
@ mbomb007 Não entendo muito bem a notação big-o, mas acho que uma única iteração é O (n). Multiplique isso pelas piores n iterações e você obtém O (n ^ 2) (pior caso; o melhor caso seria O (n), eu acho, para uma única iteração).
ETHproductions

1
Que soa bem para mim, no entanto, é importante ressaltar que a reversão de uma matriz não é uma operação muito eficiente, por isso é um processo lentoO(n^2)
DJMcMayhem

2
O @WheatWizard que inverte uma matriz não requer espaço para uma cópia da matriz, apenas espaço para um único elemento. e é O(n). troque o primeiro e o último elementos, depois troque o segundo e o segundo últimos elementos, etc., quando você chegar à parada do meio.
Jasen

A reversão é O(n), mas a reversão pode ser incorporada diretamente no algoritmo (é o que minha resposta JS faz); como cada iteração faz um loop sobre cada item da matriz uma vez, uma única iteração é O(n). (Eu acho que ...) #
22416 ETHproductions

Respostas:


19

JavaScript (ES6), 64 bytes

f=([n,...a],z=[],q=[n,...z])=>a+a?n<a[0]?[...q,...f(a)]:f(a,q):q

Recursão FTW! O algoritmo básico em uso aqui é acompanhar a execução atual não ascendente em uma matriz, "retornando" sempre que um elemento ascendente for encontrado. Fazemos isso recursivamente, concatenando continuamente os resultados, até ficar sem itens. Ao criar cada execução em sentido inverso (em [n,...z]vez de [...z,n]), podemos evitar a longa .reverse()sem nenhum custo.

Snippet de teste


Você pode explicar como sua matriz é analisada em seu primeiro parâmetro [n,...a]. O que é n? Esse é apenas o primeiro item da sua matriz?
22416 Oliver

1
@obarakon Correct. né o primeiro item da matriz e aé o restante da matriz. Você pode encontrar mais informações aqui .
ETHproductions

Obrigado. Isso foi muito útil. Como seu primeiro parâmetro é uma matriz, por que você precisa incluir o ...a? É só assim que você pode tirar proveito n? Mais uma coisa, quando você chama f(a,q), é qdefinido como o parâmetro z?
Oliver

1
@obarakon Bem, f=([n])=>...capturaria apenas o primeiro elemento e f=([n,a])=>...capturaria apenas o primeiro ne o segundo a. Outra maneira de fazer o f=([n,...a])=>,,,que seria f=a=>(n=a.unshift(),....
ETHproductions

1
E uma vez que zé o segundo parâmetro na função, quando f(a,q)é chamado, o fvê como z. Espero que isto ajude!
ETHproductions


11

Gelatina , 8 bytes

Ṁ;<œṗ³UF

Experimente online!

Explicação:

Ṁ;         Prepend the list [a1, a2… an] with its maximum.
  <        Elementwise compare this with the original list:
           [max(a) < a1, a1 < a2, …, a(n-1) < an, an]
           The first element is always 0.
   œṗ³     Partition the original list (³) at the indices
           of the non-zero values in the working list.
           (The spurious `an` at the end of the left argument,
           resulting from comparing lists of different sizes,
           is ignored by this operation, thankfully.)
      U    Reverse each part.
       F   Flatten.

1
Eu estava prestes a clicar em Salvar edições quando vi sua resposta ... Muito bem.
Dennis

@ Dennis Heh, então você adicionou o Dyalog particionado, mas e a partição APL2?
Adám 22/12/16

11

JavaScript (ES6), 70 bytes

Claro, isso já é derrotado pela resposta da ETHproductions , mas é o melhor que eu poderia chegar até agora sem usar recursão.

a=>a.map((n,i)=>a[x=[...o,...r=[n,...r]],i+1]>n&&(o=x,r=[]),r=o=[])&&x

Nota: A inicialização de ambos re oexatamente do mesmo objeto com r = o = []pode parecer uma ideia perigosa. Mas é seguro fazer isso aqui porque ré imediatamente atribuída sua própria instância (contendo o primeiro elemento de a) na primeira iteração com r = [n, ...r].

Casos de teste


2
Não se preocupe, adoro ver abordagens diferentes. E um muitas vezes acaba se tornando mais curto do que o outro depois de golfe :-)
ETHproductions

8

MATL , 15 bytes

lidO>vYsGhXSOZ)

Entrada é um vetor de coluna, com o formato [5; 2; 7; 6; 4; 1; 3](ponto e vírgula é o separador de linhas).

Experimente online!

Tome a entrada [5; 2; 7; 6; 4; 1; 3]como um exemplo.

Explicação

l     % Push 1
      % STACK: 1
i     % Push input
      % STACK: 1, [5; 2; 7; 6; 4; 1; 3]
d     % Consecutive differences
      % STACK: 1, [-3; 5; -1; -2; -3; 2]
O>    % Test if greater than 0, element-wise
      % STACK: 1, [0; 1; 0; 0; 0; 1]
v     % Concatenate vertically
      % STACK: [1; 0; 1; 0; 0; 0; 1]
Ys    % Cumulative sum
      % STACK: [1; 1; 2; 2; 2; 2; 3]
G     % Push input again
      % STACK: [1; 1; 2; 2; 2; 2; 3], [5; 2; 7; 6; 4; 1; 3]
h     % Concatenate horizontally
      % STACK: [1 5; 1 2; 2 7; 2 6; 2 4; 2 1; 3 3]
XS    % Sort rows in lexicographical order
      % STACK: [1 2; 1 5; 2 1; 2 4; 2 6; 2 7; 3 3]
OZ)   % Get last column. Implicitly display
      % STACK: [2; 5; 1; 4; 6; 7; 3]

Traduzi sua resposta para Octave e me salvei 31 bytes!
rahnema1

7

Mathematica, 30 27 bytes

3 bytes salvos devido ao @Martin Ender .

Join@@Sort/@Split[#,#>#2&]&

Função anônima. Pega uma lista de números como entrada e retorna uma lista de números como saída.


Bata em mim! :)
Greg Martin

5

Python 2, 100 bytes

Um golfe realmente péssimo, mas eu queria postar minha solução (não se supera simplesmente Dennis) ...

d=input();L=[];x=0;d+=-~d[-1],
for i in range(1,len(d)):
 if d[i]>d[i-1]:L+=d[x:i][::-1];x=i
print L

Teste em repl.it!

A entrada deve ser fornecida como uma lista literal de Python, como [5, 3, 4, 2, 6, 1].

A idéia básica é fazer uso pesado da sintaxe de fatia do Python, cortando cada seção necessária da matriz, revertendo-a e adicionando-a à nova matriz.


Eu acho que a primeira linha pode ser d,L,x=input(),[],0;d+=....
Daniel

@Dopapp que é exatamente o mesmo número de bytes
FlipTack


4

Retina , 163 bytes

Sim, eu sei como isso é horrível. Apoiar zeros e negativos foi super divertido. A contagem de bytes assume a codificação ISO 8859-1.

\d+
$*
(?<=-1*)1
x
-

x,1
x¶1
\b(1+),(1+\1)\b
$1¶$2
,,1
,¶1
x,(¶|$)
x¶¶
(?<=\b\1x+(?=,(x+))),\b
¶
O%$#`.(?=(.*))
$.1
+`¶
,
\bx
-x
(\w+)
$.1
^,
0,
,$
,0
,,
,0,
^$
0

Experimente online

Explicação:

\d+                         # Convert to unary
$*
(?<=-1*)1                   # Replace negatives with x's instead of 1's
x
-                           # Remove minus sign

x,1                         # Separate if negative before positive
x¶1
\b(1+),(1+\1)\b             # or greater positive follows a positive
$1¶$2
,,1                         # or positive follows a zero
,¶1
x,(¶|$)                     # or zero follows a negative
x¶¶
(?<=\b\1x+(?=,(x+))),\b     # or negative follows a negative of greater magnitude.
¶
O%$#`.(?=(.*))              # Swear at the input, then reverse each line
$.1
+`¶                         # Remove breaks, putting commas back
,
\bx                         # Put the minus signs back
-x
(\w+)                       # Replace unary with length of match (decimal)
$.1
^,                          # Do a bunch of replacements to resurrect lost zeros
0,
,$
,0
,,
,0,
^$
0

4

05AB1E , 19 18 16 14 bytes

Economizou 2 bytes usando o truque de classificação de Luis Mendo

ü‹X¸ì.pO¹)ø{ø¤

Experimente online!

Explicação

Exemplo de entrada [5, 2, 7, 6, 4, 1, 3]

ü‹               # pair-wise less-than
                 # STACK: [0, 1, 0, 0, 0, 1]
  X¸ì            # prepend a 1
                 # STACK: [1, 0, 1, 0, 0, 0, 1]
     .p          # prefixes
       O         # sum
                 # STACK: [1, 1, 2, 2, 2, 2, 3]
        ¹        # push input
                 # STACK: [1, 1, 2, 2, 2, 2, 3], [5, 2, 7, 6, 4, 1, 3]
         )       # wrap stack in list
                 # STACK: [[1, 1, 2, 2, 2, 2, 3], [5, 2, 7, 6, 4, 1, 3]]
          ø      # zip
                 # STACK: [[1, 5], [1, 2], [2, 7], [2, 6], [2, 4], [2, 1], [3, 3]]
           {     # sort
                 # STACK: [[1, 2], [1, 5], [2, 1], [2, 4], [2, 6], [2, 7], [3, 3]]
            ø    # zip
                 # STACK: [[1, 1, 2, 2, 2, 2, 3], [2, 5, 1, 4, 6, 7, 3]]
             ¤   # tail
                 # OUTPUT: [2, 5, 1, 4, 6, 7, 3]

Solução anterior de 16 bytes

Dü‹X¸ì.pO.¡€g£í˜

Aqueles quebras de linha explicaram isso maravilhosamente ... :-P #
Stewie Griffin

@StewieGriffin: Sim, eu mudei o código e postei antes de reescrever a explicação: P
Emigna

4

JavaScript (ECMA 6), 121 128 125 119 108 bytes

f=a=>{p=a[0],c=[],b=[];for(e of a){e>p&&b.push(c.reverse(c=[]));c.push(p=e)}return[].concat.call([],...b,c)}

A expressão lambda usa um único Arrayparâmetro a,.

Obrigado a @ETHproductions por me ajudar a ver meu primeiro erro.


Agradável! Eu acho que você pode fazer return(b+","+c).split`,` para salvar alguns bytes no final.
ETHproductions

1
Melhor ainda, você pode usar em c.unshiftvez de c.pushremover a necessidade de reverter c. Depois disso, obtive 94 bytes .
ETHproductions

3

Ruby, 60 55 bytes

s=->x{x.slice_when{|p,q|p<q}.map{|z|z.reverse}.flatten} 

Praticamente o que o desafio pediu. Eu defini um lambda s, que pega um array xe o divide (fatias) em pedaços menores, onde o seguinte elemento seria maior que. Isso retorna um enumerador, que podemos chamar de mapear e reverter a ordem das peças, antes de finalmente juntar tudo com achatar, que concatena os elementos da ordem definida em uma matriz.

Testes

p s[[1]]===[1]
p s[[1, 1]]===[1, 1]
p s[[1, 2]]===[1, 2]
p s[[2, 1]]===[1, 2]
p s[[2, 3, 1]]===[2, 1, 3]
p s[[2, 1, 3]]===[1, 2, 3]
p s[[2, 1, 2]]===[1, 2, 2]
p s[[2, 1, 1]]===[1, 1, 2]
p s[[3, 1, 1, 2]]===[1, 1, 3, 2]
p s[[3, 2, 1, 2]]===[1, 2, 3, 2]
p s[[3, 1, 2, 2]]===[1, 3, 2, 2]
p s[[1, 3, 2, 2]]===[1, 2, 2, 3]
p s[[1, 0, 5, -234]]===[0, 1, -234, 5]
p s[[1, 0, 1, 0, 1]]===[0, 1, 0, 1, 1]
p s[[1, 2, 3, 4, 5]]===[1, 2, 3, 4, 5]
p s[[5, 4, 3, 2, 1]]===[1, 2, 3, 4, 5]
p s[[2, 1, 5, 4, 3]]===[1, 2, 3, 4, 5]
p s[[2, 3, 1, 5, 4]]===[2, 1, 3, 4, 5]
p s[[5, 1, 4, 2, 3]]===[1, 5, 2, 4, 3]
p s[[5, 2, 7, 6, 4, 1, 3]]===[2, 5, 1, 4, 6, 7, 3]
p s[[-5, -2, -7, -6, -4, -1, -3]]===[-5, -7, -2, -6, -4, -3, -1]
p s[[14, 5, 3, 8, 15, 7, 4, 19, 12, 0, 2, 18, 6, 11, 13, 1, 17, 16, 10, 9]]===[3, 5, 14, 8, 4, 7, 15, 0, 12, 19, 2, 6, 18, 11, 1, 13, 9, 10, 16, 17]

1
Bem-vindo, boa <s> primeira </s> segunda resposta, verifique o seguinte: codegolf.stackexchange.com/questions/363/…
GB

Muito obrigado. Transformou isso em um lambda, conforme sugerido no link que você forneceu, e salvou 5 bytes dessa maneira.
manonthemat

2

Braquilog , 10 bytes

~c:{>=r}ac

Experimente online!

Explicação

~c            Deconcatenate the Input
  :{>=r}a     Each resulting sublist must be non-increasing, and then reverse it
         c    Concatenate

Os Brachylog's c, quando executados ao contrário, necessariamente tentam se dividir em menos listas primeiro?

@ ais523 sim, faz.
Fatalize

1

Dyalog APL , 7 15 bytes

Requer ⎕ML←3, que é padrão em muitos sistemas. *

{∊⌽¨⍵⊂⍨1+⍵-⌊/⍵}

alistar-se (achatar)

⌽¨ cada um invertido

⍵⊂⍨ o argumento particionado * cortando onde cada elemento correspondente é maior que seu antecessor em

1+ um mais

⍵- o argumento menos

⌊/⍵ o menor elemento do argumento


A solução antiga de 7 bytes falha com números inteiros não positivos:

Requer ⎕ML←3, que é padrão em muitos sistemas. *

∊⌽¨⊆⍨⎕

alistar (achatar) o

⌽¨ cada um invertido

⊂⍨ particionado automaticamente *


* Partition ( ) é uma função que corta seu argumento da direita onde o argumento da esquerda correspondente é maior que o anterior. (Infelizmente, ele aceita apenas números inteiros não negativos e zero tem um significado especial.) Na versão 16, essa funcionalidade de está disponível em todos os sistemas (mesmo naqueles em que ⎕ML≠3), usando o glifo .


1

Haskell, 49 bytes

(a:b)%l|any(<a)l=l++b%[a]|1<2=b%(a:l)
_%l=l
(%[])

Exemplo de uso: (%[]) [5,2,7,6,4,1,3]-> [2,5,1,4,6,7,3].

Abordagem recursiva. A função %leva a lista de entrada como seu primeiro parâmetro e um acumulador lque monitora até agora o pedaço não ascendente (em ordem inversa). O caso base é alcançado quando a lista de entrada está vazia e o resultado é o acumulador. Se a lista de entrada não estiver vazia e o primeiro elemento anão se encaixar no chunk atual ( any(<a)l), retorne o acumulador e acrescente uma chamada recursiva no restante da lista e acomo o novo acumulador ( l++b%[a]). Caso contrário, faça uma chamada recursiva no restante da lista e aanexado ao acumulador ( b%(a:l)). A função principal (%[])chama %com um acumulador vazio.



1

R, 64 bytes

cat(unlist(lapply(split(x<-scan(),cumsum(c(F,diff(x)>0))),rev)))

Lê a entrada de stdin. Dividimos a entrada em uma lista de vetores usando a split()qual requer uma variável de fator que agrupa a entrada. O fator é criado pela soma cumulativa do vetor lógico para o qual a diferença é positiva.

Considere o vetor:

x=c(5, 2, 7, 6, 4, 1, 3)

Agora, pegar a diferença e preceder Fexecutando y=c(F,diff(x)>0)geraria o seguinte vetor lógico:

[1] FALSE FALSE  TRUE FALSE FALSE FALSE  TRUE

Tomando a soma cumulativa cumsum(y)produz um vetor em que cada grupo é representado por um fator único sobre o qual podemos combinar com a splitfunção:

[1] 0 0 1 1 1 1 2

60 bytes usando em diffinvvez de cumsum.
Giuseppe

1

Oitava, 75 44 bytes

Baseado na resposta MATL de @LuisMendo

@(a)sortrows([cumsum([1;diff(a)>0]),a])(:,2)

Experimente Online!

Resposta anterior

@(a)[fliplr(mat2cell(f=fliplr(a),1,diff(find([1,diff(f)<0,numel(a)])))){:}]

Experimente Online!

inverter a matriz

f=fliplr(a)

tome a primeira diferença de f

d = diff(f);

encontre a posição de onde o próximo elemento é menor que o elemento anterior

p=find([1,diff(f)<0,numel(a)])

primeira diferença das posições retorna o comprimento de cada sub-matriz

len=diff(p)

use o comprimento de cada sub-matriz mat2cellpara dividir a matriz em uma lista aninhada de matrizes

nest = mat2cell(f,1,len);

reverter a lista aninhada

rev_nest = fliplr(nest) 

achatar a lista aninhada

[rev_nest{:}]


0

Perl 6 , 59 bytes

{map |+«*.[0].reverse,m/:s([(\-?\d+)<?{[>=] $0}>] +)+/[0]}

Solução baseada em Regex.
Porque este é Sparta Perl !!

  • m/ /: Stringify a matriz de entrada e corresponda a uma regex contra ela.
  • (\-? \d+): Combine um número e capture-o como $0.
  • <?{ [>=] $0 }>: Asserção de largura zero que corresponde apenas se todas as $0capturadas até agora na sub-correspondência atual estiverem em ordem não crescente.
  • ([ ] +)+: Repita as duas últimas etapas o mais rápido possível; caso contrário, inicie uma nova sub-correspondência.
  • map , [0]: Itera sobre as sub-correspondências.
  • |+«*.[0].reverse: Para cada um, pegue a lista de valores correspondidos por $0, inverta-os, force os valores a números ( ) e coloque-os na lista externa ( |).

Perl 6 , 63 bytes

sub f(\a){flat $_,f a[+$_..*]with first {[<=] $_},:end,[\R,] a}

Solução de processamento de lista recursiva.
Mais trabalhoso do que eu esperava.
Mesmo que o idioma tenha muitos recursos convenientes, parece não haver nenhum para particionamento de lista (por exemplo, como Ruby slice_whenou Haskell takeWhile).


0

Empilhados , não concorrentes, 34 bytes

Ainda constantemente desenvolvendo essa linguagem.

{e.b:e b last<}chunkby$revmap flat

O argumento está no TOS. Experimente aqui!

chunkbypega uma função e coleta matrizes de dados contíguos que satisfazem a função. A função então é:

{e.b:e b last<}
{e.b:         }  function with arguments [e, <unused>, b]--the element, <the index>, and the
                 chunk being built
     e       <   check if e is less than
       b last    the last element of b

Isso fornece uma matriz estritamente decrescente.

$revmapé basicamente [rev]mape reverte cada item.

flat finalmente nivela a matriz.


Alguma diversão para realmente classificar a matriz:

[{e.b:e b last<}chunkby$revmap flat] @:sortstep
[$sortstep periodloop] @:sort

10:> @arr
arr out
arr shuf @arr
arr out
arr sort out

Isso gera (por exemplo):

(0 1 2 3 4 5 6 7 8 9)
(4 5 1 0 6 7 2 8 9 3)
(0 1 2 3 4 5 6 7 8 9)

0

Python, 151 139 bytes

Guardado 12 bytes graças a @ Flp.Tkc!

Em nenhum lugar perto de @ Flp.Tkc, muito menos ...

def s(l):
 r=[];i=j=0
 while j<len(l)-1:
  if l[j+1]>l[j]:r+=l[i:j+1][::-1],;i=j+1
  j+=1
 r+=l[i:j+1][::-1],;return[i for s in r for i in s]

Em vez de usar o acréscimo, use += data,a vírgula à direita cria implicitamente uma tupla, que é concatenada com a lista, adicionando os dados como o último elemento da lista. Nesse contexto, façar+=l[i:j+1][::-1],
FlipTack

0

Python 2, 74 bytes

b=[];c=[];a+=9e9,
for i in a[:-1]:
 b=[a.pop(0)]+b
 if b[0]<a[0]:c+=b;b=[]

Entrada a, saída emc


0

Python 3, 191 bytes

a=[int(i)for i in input().split()]
while a!=sorted(a):
 b=[[]]
 for i,j in enumerate(a):
  if a[i-1]<j:b+=[[j]]
  else:b[-1]+=[j]
 a=[]
 for l in[k[::-1]for k in b]:a+=[k for k in l]
print(a)

Não tenho certeza se o uso da sortedfunção para verificação é permitido aqui, mas não consegui pensar em uma boa razão para isso, e isso reduziu minha contagem de bytes em ~ 30 bytes.


0

Clojure, 105 bytes

#(filter number?(mapcat reverse(partition-by not(mapcat(fn[[a b]][a(< b a)])(partition 2 1(conj % 1))))))

Partições em pares em números consecutivos, coloca trueou falseentre elas, as partições notpara truee números se tornam falsee false true, inverte as partições e mantém os valores numéricos.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.