Coprendo uno Skyline con pennellate


43

Dato un elenco di altezza dello skyline intero non negativo, rispondi a quante pennellate orizzontali alte 1 unità ininterrotte sono necessarie per coprirlo.

[1,3,2,1,2,1,5,3,3,4,2], visualizzato come:

      5    
      5  4 
 3    5334 
 32 2 53342
13212153342

ha bisogno di nove pennellate:

      1    
      2  3 
 4    5555 
 66 7 88888
99999999999

Esempi

[1,3,2,1,2,1,5,3,3,4,2]9

[5,8]8

[1,1,1,1]1

[]0

[0,0]0

[2]2

[2,0,2]4

[10,9,8,9]11


Per utenti interessati ad alta reputazione: in base a questo come a questo .
Adám

2
Quindi, tutte le pennellate sono orizzontali?
martedì

1
@tsh buon punto. Aggiunto.
Adám

Non era codegolf, ma avevo una domanda per un test del codice di intervista circa un anno fa.
luizfzs

Risposte:


35

JavaScript (Node.js) , 38 byte

a=>a.map(v=>(n+=v>p&&v-p,p=v),p=n=0)|n

Provalo online!

Semplicemente un algoritmo avido che scansiona da sinistra a destra, disegna solo linee se necessario e disegnalo il più a lungo possibile.

Grazie Arnauld, risparmia 2 3 byte


@Arnauld bella cattura. totalmente dimenticato.
martedì

Come te ne sei reso conto?
Adám,

@ Adám Niente di magico. La prima volta che ho letto la domanda sono stato confuso da come cercare fino a quando mi rendo conto che tutte le linee sono solo orizzontali. E poi questa formula appena venuto in mente naturalmente ....
TSH

4
la magia sembra una parola adatta per descrivere quel processo.
Adám,

1
Mentre questa è l'origine dell'algoritmo ormai ampiamente usato, è spiegato qui .
Adám,

28

05AB1E ,  8 7  5 byte

Salvato 2 byte grazie a @Adnan

0š¥þO

Provalo online!

Come?

Questo sta usando l'algoritmo che è stato trovato per la prima volta da @tsh . Se ti piace questa risposta, assicurati di votare anche la loro risposta !

Ogni volta che un grattacielo è più basso o più alto del precedente, può essere dipinto "gratuitamente" semplicemente estendendo le pennellate.

Ad esempio, dipingere i grattacieli B e C nella figura seguente non costa nulla.

E

edifici

Per il primo grattacielo, abbiamo sempre bisogno di tante pennellate quanti sono i pavimenti.

Trasformando questo in matematica:

S=h0+i=1nmax(hihi1,0)

Se anteponiamo all'elenco, questo può essere semplificato per:0

S=i=1nmax(hihi1,0)

Commentate

0š¥þO     # expects a list of non-negative integers  e.g. [10, 9, 8, 9]
0š        # prepend 0 to the list                    -->  [0, 10, 9, 8, 9]
  ¥       # compute deltas                           -->  [10, -1, -1, 1]
   þ      # keep only values made of decimal digits
          # (i.e. without a minus sign)              -->  ["10", "1"]
    O     # sum                                      -->  11

Penso che 0š¥ʒd}Oti salvi un byte.
Mr. Xcoder,

@ Don'tbeax-tripledot Stavo modificando la mia risposta esattamente quando ho visto il tuo commento;)
Arnauld

4
Bella spiegazione
Adám

1
La sostituzione ʒd}con þdovrebbe farti risparmiare due byte.
Adnan,

@Adnan Ah, carino. Grazie!
Arnauld


7

Haskell , 32 byte

(0%)
p%(h:t)=max(h-p)0+h%t
p%_=0

Provalo online!

Un miglioramento della soluzione di Lynn che tiene traccia dell'elemento precedente pinvece di guardare l'elemento successivo. Ciò rende il caso base e la chiamata ricorsiva più brevi in ​​cambio della necessità di invocare (0%).

max(h-p)0potrebbe essere max h p-pdella stessa lunghezza.



5

K (oK) , 12 7 byte

-5 byte grazie a ngn!

Una porta k (oK) della soluzione 05AB1E di Arnauld (e la soluzione JavaScript di tsh):

+/0|-':

Provalo online!

J , 15 byte

Porta AJ della soluzione 05AB1E di Arnauld (e soluzione JavaScript di tsh):

1#.0>./2-~/\0,]

Provalo online!

La mia ingenua soluzione:

J , 27 byte

1#.2(1 0-:])\0,@|:@,~1$~"0]

Provalo online!


2
OK: ogni precedente ( ':) utilizza un elemento di identità implicito ( 0per -) prima dell'elenco, quindi 0,non è necessario. puoi ometterlo { x}per renderlo una composizione:+/0|-':
ngn

@ngn Grazie! Apparentemente ho dimenticato questo:Some primitive verbs result in a different special-cased initial value: +, *, - and & are provided with 0, 1, 0 or the first element of the sequence, respectively
Galen Ivanov il

5

Haskell , 34 32 byte

2 byte tagliati da Lynn

g x=sum$max 0<$>zipWith(-)x(0:x)

Provalo online!

Quindi per iniziare abbiamo zipWith(-). Questo prende due elenchi e produce un nuovo elenco delle loro differenze a coppie. Quindi lo combiniamo con xe (0:x). (0:)è una funzione che aggiunge zero all'inizio di un elenco e combinandolo con zipWith(-)otteniamo le differenze tra gli elementi consecutivi di tale elenco con uno zero in primo piano. Quindi giriamo tutti quelli negativi a zero con (max 0<$>). Questo crea un nuovo elenco in cui ogni elemento è il numero di nuovi tratti che devono essere avviati in ogni torre. Per ottenere il totale, li sommiamo semplicemente sum.


2
g x=sum$max 0<$>zipWith(-)x(0:x)è di 32 byte :)
Lynn il

Come èsum.zipWith((max 0.).(-))<*>(0:)
Lynn

@Lynn La tua seconda avrà bisogno di parentesi extra poiché .ha una precedenza più alta di <*>.
Wheat Wizard

3

Japt , 8 byte

-2 byte da @Shaggy

mîT Õ¸¸è

Spiegazione

mîT Õ¸¸è      Full program. Implicit input U
                e.g. U = [2,0,2]
mîT             Map each item X and repeat T(0) X times
                     U = ["00","","00"]
    Õ           Transpose rows with columns
                     U = ["0 0","0 0"]
     ¸¸         Join using space and then split in space
                     U = ["0","0","0","0"]
        è       Return the count of the truthy values

Provalo online!


8 byte:mîT Õ¸¸è
Shaggy

1
A A.y()proposito, buon uso dell 'imbottitura.
Shaggy

3

MATL , 8 byte

0whd3Y%s

Provalo online!

Praticamente l'algoritmo di @ Arnauld. Salvato un byte (grazie a @LuisMendo) eseguendo il casting uint64anziché selezionare )voci positive.


3

Gelatina , 5 byte

Una porta della mia risposta 05AB1E , che a sua volta è simile alla risposta @tsh JS .

ŻI0»S

Provalo online!

Commentate

ŻI0»S    - main link, expecting a list of non-negative integers  e.g. [10, 9, 8, 9]
Ż        - prepend 0                                             -->  [0, 10, 9, 8, 9]
 I       - compute the deltas                                    -->  [10, -1, -1, 1]
  0»     - compute max(0, v) for each term v                     -->  [10, 0, 0, 1]
    S    - sum                                                   -->  11

3

Japt , 7 6 byte

änT fq

Provalo

1 byte salvato grazie a Oliver.

änT xwT    :Implicit input of integer array
än         :Consecutive differences / Deltas
  T        :  After first prepending 0
    f      :Filter elements by
     q     :  Square root (The square root of a negative being NaN)
           :Implicitly reduce by addition and output


Bello, @Oliver; non ci avrei pensato.
Shaggy


2

Retina 0.8.2 , 21 byte

\d+
$*
(1+)(?=,\1)

1

Provalo online! Il link include casi di test. Spiegazione:

\d+
$*

Converti in unario.

(1+)(?=,\1)

Elimina tutte le sovrapposizioni con la torre successiva, che non richiede un nuovo tratto.

1

Conta i colpi rimanenti.


2

Lisp comune, 88 87 byte

(lambda(s)(let((o 0))(dolist(c s)(incf o(max 0 c))(mapl(lambda(y)(decf(car y)c))s))o))

non minified

(lambda (skyline)
  (let ((output 0))
    (dolist (current-skyscraper-height skyline)
      (incf output (max 0 current-skyscraper-height))
      (mapl (lambda (skyscraper)
              (decf (car skyscraper) current-skyscraper-height))
            skyline))
    output)))

Provalo

Quando una torre è dipinta, ci vogliono un numero di pennellate pari alla sua altezza. Queste pennellate si traducono in tutte le seguenti, che è indicato qui sottraendo l'altezza della torre corrente da tutte le altre torri (e se stessa, ma non importa). Se una torre successiva è più corta, verrà spostata su un numero negativo e questo numero negativo verrà successivamente sottratto dalle torri che seguono (indicando pennellate che non potevano essere tradotte da una torre precedente a quelle successive). In realtà sottrae solo il numero da tutte le altezze della torre, comprese quelle precedenti, ma questo non importa perché non guardiamo di nuovo quelle precedenti.


Benvenuti in PPCG. Potresti forse fornire un link a un ambiente di test online per una facile verifica?
Jonathan Frech

Si assolutamente. rextester.com/TKBU14782 La risposta verrà aggiornata a breve
Charlim

Molto bene. +1 per un bel post funzionante. Divertiti a giocare a golf.
Jonathan Frech,

1

05AB1E , 13 10 byte

Z>Lε@γPO}O

Provalo online o verifica tutti i casi di test .

Spiegazione:

Z            # Get the maximum of the (implicit) input-list
 >           # Increase it by 1 (if the list only contains 0s)
  L          # Create a list in the range [1, max]
   ε         # Map each value to:
    @        #  Check if this value is >= for each value in the (implicit) input
     γ       #  Split into chunks of adjacent equal digits
      P      #  Take the product of each inner list
       O     #  Take the sum
        }O   # And after the map: take the sum (which is output implicitly)

1

C # (compilatore interattivo Visual C #) con flag /u:System.Math, 47 byte

n=>n.Select((a,i)=>i<1?a:Max(a-n[i-1],0)).Sum()

Provalo online!

Vecchia versione, con bandiera /u:System.Math, 63 byte

n=>n.Aggregate((0,0),(a,b)=>(a.Item1+Max(0,b-a.Item2),b)).Item1

Sento che questa soluzione è più elegante della prima. Passa attraverso l'array con una tupla a due valori come valore iniziale, raccogliendo valori e memorizzando il valore prima di esso nella seconda parte della tupla.

Provalo online!


1

Pyth, 8 byte

s>#0.++0

Ancora un'altra porta della meravigliosa risposta di @ tsh . Prende la somma ( s) dei valori positivi ( >#0) dei delta (. +) Dell'input con 0 anteposto ( +0Q, dedotto Q inferito).

Provalo online qui o verifica tutti i casi di test contemporaneamente qui .

Metodo di unione delle stringhe, 10 byte

Questa era la soluzione che ho scritto prima di sfogliare le altre risposte.

lcj.t+d*LN

Suite di test.

lcj.t+d*LNQ   Implicit: Q=eval(input()), b=<newline>, N=<quote mark>
              Trailing Q inferred
        L Q   Map each element of Q...
       * N    ... to N repeated that many times
     +b       Prepend a newline
   .t         Transpose, padding with spaces
  j           Join on newlines
 c            Split on whitespace
l             Take the length, implicit print

1

Clojure, 50 byte

#((reduce(fn[[s n]i][(+(max(- i n)0)s)i])[0 0]%)0)

Provalo online! (Perché questo non stampa nulla?)

#( ; begin anonymous function
    (reduce
        (fn [[s n] i] ; internal anonymous reducing function, destructures accumulator argument into a sum and the previous item
            [(+ (max (- i n) 0) s ; the sum part of the accumulator becomes the previous sum plus the larger of zero and the difference between the current number and the last one, which is how many new strokes need to be started at this point
            i]) ; ...and the previous item part becomes the current item
        [0 0] ; the initial value of the accumulator gives no strokes yet, and nothing for them to cover yet
        %) ; reduce over the argument to the function
    0) ; and get the sum element of the last value of the accumulator.

Benvenuti in PPCG! Non so nulla di Clojure, ma una rapida ricerca mostra che dovrai valutare il ciclo pigro. Provalo online! (Suggerimento: è possibile utilizzare il pulsante di collegamento per formattare automaticamente la risposta). Spero che rimani in giro e ti diverta!
Jo King,


0

MATL , 15 14 13 byte

ts:<~"@Y'x]vs

L'input è un vettore di colonna, che utilizza ;come separatore.

Provalo online! Oppure verifica tutti i casi di test .

Spiegazione

t       % Implicit input: column vector. Duplicate
s       % Sum
:       % Range from 1 to that. Gives a row vector
<~      % Greater or equal? Element-wise with broadcast
"       % For each column
  @     %   Push current columnn
  Y'    %   Run-length encoding. Gives vector of values (0, 1) and vector of lengths
  x     %   Delete vector of lengths
]       % End
v       % Vertically concatenate. May give an empty array
s       % Sum. Implicit display

0

Perl 5, 21 byte

$\+=$_>$'&&$_-$';//}{

TIO

Come

  • -p+ }{+ $\trucco
  • //corrisponde a una stringa vuota in modo che per la riga successiva postmatch $'conterrà la riga precedente
  • $\+=$_>$'&&$_-$'accumulare differenze tra la riga corrente e la precedente se la corrente è maggiore della precedente (potrebbe anche essere scritta $\+=$_-$' if$_>$', ma perl non analizza $\+=$_-$'if$_>$'la stessa)


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.