Quante cime nella mia catena montuosa?


27

Un elenco di numeri interi positivi può essere visualizzato come una catena montuosa quantizzata in cui ciascuna voce dell'elenco rappresenta l'altezza di una sezione verticale delle montagne.

Ad esempio, l'elenco

1, 2, 2, 3, 4, 3, 5, 3, 2, 1, 2, 3, 3, 3, 2, 2, 1, 3

può diventare la gamma

      x
    x x      
   xxxxx   xxx   x
 xxxxxxxx xxxxxx x
xxxxxxxxxxxxxxxxxx

(Le persone meno poetiche potrebbero chiamarlo un grafico a barre, ma sto divagando.)

La domanda in questa sfida è: quante cime si trovano nella catena montuosa di un elenco arbitrario? In sostanza, quanti massimi locali sono presenti nell'elenco?

Un picco è definito come una sezione contigua di una o più colonne della catena montuosa tutte uguali in altezza, dove le colonne immediatamente a sinistra e a destra sono più basse in altezza.

È facile dire visivamente che l'esempio ha quattro picchi in queste posizioni tra parentesi:

1, 2, 2, 3, (4), 3, (5), 3, 2, 1, 2, (3, 3, 3), 2, 2, 1, (3)

Nota come la (3, 3, 3)sezione del plateau conta come un picco perché è un insieme contiguo di colonne uguali in altezza, più alte delle sue colonne vicine.

Anche l'ultimo (3)conta come picco perché, ai fini di questa sfida, definiremo il vicino sinistro della colonna più a sinistra e il vicino destro della colonna più a destra per essere entrambi altezza zero.

Ciò significa che una lista con un solo valore, per esempio 1, 1, 1, può essere interpretata come 0, 1, 1, 1, 0, e quindi ha un picco, non nessuno: 0, (1, 1, 1), 0.

L'unica lista con zero picchi è la lista vuota.

Sfida

Scrivi una funzione o un programma che contiene un elenco arbitrario di numeri interi positivi e stampa o restituisce il numero di picchi nella catena montuosa corrispondente.

Vince il codice più breve in byte. Tiebreaker è post precedente.

Casi test

Input List -> Output Peak Count
[empty list] -> 0
1, 1, 1 -> 1
1, 2, 2, 3, 4, 3, 5, 3, 2, 1, 2, 3, 3, 3, 2, 2, 1, 3 -> 4
1 -> 1
1, 1 -> 1
2, 2, 2, 2, 2 -> 1
90 -> 1
2, 1, 2 -> 2
5, 2, 5, 2, 5 -> 3
2, 5, 2, 5, 2, 5, 2 -> 3
1, 2, 3, 4 -> 1
1, 2, 3, 4, 1, 2 -> 2
1, 3, 5, 3, 1 -> 1
7, 4, 2, 1, 2, 3, 7 -> 2
7, 4, 2, 1, 2, 1, 2, 3, 7 -> 3
1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2 -> 10
1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1 -> 10
2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2 -> 10
1, 3, 3, 3, 1, 3, 3, 1, 3, 1, 3, 3, 3, 3, 1 -> 4
12, 1, 2, 1, 2, 3, 3, 3, 2, 4, 4, 4, 1, 5, 5, 4, 7, 9 -> 6
87, 356, 37673, 3676, 386, 909, 909, 909, 909, 454, 909, 909 -> 3
87, 356, 37673, 3676, 386, 909, 909, 909, 909, 454, 909, 908, 909 -> 4

Quindi, l'altopiano può essere arbitrariamente lungo?
nicael,

@nicael Sì, potrebbe essere
Calvin's Hobbies,

Possiamo prendere l'input come un array, non come una stringa?
nicael,

@nicael Sì, qualsiasi cosa ragionevole
Calvin's Hobbies

Risposte:


2

Pyth, 18 byte

su_>VGtG2eMr++ZQZ8

Basato sulla soluzione più che ripetuta di @ PeterTaylor, ma con una svolta.

++ZQZ: Aggiunge zeri su entrambi i lati.

eMr ... 8: Rimuove le ripetizioni.

u ... 2 ...: Applica quanto segue due volte:

>VGTG: Mappa ogni coppia di numeri per stabilire se sono in ordine decrescente.

_: E viceversa.

A 1 nell'uscita corrisponde a a 1, 0nella fase precedente, che corrisponde a < b > call'ingresso a causa dell'inversione.

s: Somma (e stampa)


10

CJam ( 32 26 24 21 byte)

0q~0]e`1f=2ew::>2,/,(

L'input previsto è numeri separati da spazi.

Demo online ; suite di test completa (l'output previsto è un 1caso di test).

Grazie a Martin per avermi informato che l'attuale versione di CJam migliora uno degli operatori utilizzati, risparmiando 2 caratteri; e per un ulteriore risparmio di 3 caratteri.

Dissezione

Due fasi: deduplica, quindi identifica i massimi locali in ciascuna serie di tre.

0q~0]      e# Put the input in an array wrapped in [0 ... 0]
e`1f=      e# Use run-length encoding to deduplicate
2ew::>     e# Map [a b c ...] to [(a>b) (b>c) ...]
2,/        e# Split on [0 1], which since we've deduplicated occurs when (a<b) (b>c)
,(         e# Count the parts and decrement to give the number of [0 1]s

7

JavaScript (ES6), 54 51 byte

m=>m.map(n=>{h=n<p?h&&!++r:n>p||h;p=n},r=h=p=0)|r+h

Spiegazione

Accetta una serie di numeri

m=>
  m.map(n=>{       // for each number n in the mountain range
      h=
        n<p?       // if the number is less than the previous number:
          h&&      // if the previous number was greater than the number before it
          !++r     // increment the number of peaks and set h to 0
        :n>p||h;   // if the number is greater than the previous number, set h to 1
      p=n          // set p to the current number
    },
    r=             // r = number of peaks
    h=             // h = 1 if the previous number was higher than the one before it
    p=0            // p = previous number
  )|r+h            // return the output (+ 1 if the last number was higher)

Test


5

Pyth, 25 23 byte

L._M-M.:b2s<R0y-y+Z+QZZ

Spiegazione:

L              y = lambda b:
  ._M -M .:          signs of subsets
           b          of b
           2          of length 2. That is, signs of differences.

s <R              number of elements less than
     0              0 in
     y -            y of ... with zeroes removed
         y +          y of
             Z        the input with zeroes tacked on both sides
             + Q Z
       Z              

Bello. Insolitamente, un porto per CJam è più corto: 0q~0]{2ew::-:g0-}2*1-,per 22.
Peter Taylor

4

Julia, 66

x->(y=diff([0;x;0]);y=y[y.!=0];sum((y[1:end-1].>0)&(y[2:end].<0)))

Pad, differenziare: y=diff([0;x;0]).
Ignorare l'altipiani: y=y[y.!=0].
Conte +a -zero crossing: sum((y[1:end-1].>0)&(y[2:end].<0)).


3

MATLAB, 29 27 byte

@(a)nnz(findpeaks([0 a 0]))

Funzione anonima che trova i picchi nei dati e conta quanti ce ne sono. 0 viene anteposto e aggiunto ai dati per garantire che i picchi ai bordi siano rilevati secondo la domanda.

Questo funzionerà anche con Octave . Puoi provare online qui . Basta incollare il codice sopra nella riga di comando e quindi eseguirlo con ans([1,2,1,3,4,5,6,1])(o qualunque altro input).


Dato che i numeri sono sempre + ve, possiamo supporre che siano maggiori di zero, quindi possiamo salvare 2 byte usando nnzinvece di numel.


3

Python 3, 75 byte

def m(t):
 a=p=d=0
 for n in t+[0]:a+=(n<p)&d;d=((n==p)&d)+(n>p);p=n
 return a

Questo è il mio primo codegolf quindi potrebbero esserci dei posti in cui tagliarlo, specialmente la d=((n==p)&d)+(n>p)parte. Tuttavia funziona su tutti i casi di test


Questi non sono 78 byte ?
Jonathan Frech,

3

Mathematica, 42 36 33 32 byte

Grazie a Martin Büttner per aver salvato 1 byte.

Tr@PeakDetect[#&@@@Split@#,0,0]&

PeakDetect fa quasi tutto!

Casi test:

Total@PeakDetect[#&@@@Split@#,0,0]&@{12,1,2,1,2,3,3,3,2,4,4,4,1,5,5,4,7,9}
(* 6 *)
Total@PeakDetect[#&@@@Split@#,0,0]&@{87,356,37673,3676,386,909,909,909,909,454,909,908,909}
(* 4 *)

Trovo che la mia risposta sia sufficientemente diversa dalla tua per postarne un'altra.
LegionMammal978,

@ LegionMammal978 Il risultato dell'input {1} è 1, come previsto.
njpipeorgan,

Voglio dire {1, 2, 2, 3, 4, 3, 5, 3, 2, 1, 2, 3, 3, 3, 2, 2, 1, 3}
LegionMammal978

@ LegionMammal978 È difficile. Non ho trovato una soluzione.
njpipeorgan,

La mia soluzione aggiornata appiattisce semplicemente "plateau".
LegionMammal978


2

MATL , 22 byte

0ih0hdZS49+c'21*?0'XXn

Utilizza la versione corrente del linguaggio / compilatore.

Esempio

>> matl
 > 0ih0hdZS49+c'21*?0'XXn
 >
> [1, 2, 2, 3, 4, 3, 5, 3, 2, 1, 2, 3, 3, 3, 2, 2, 1, 3]
4

Spiegazione

0ih0h           % input array. Append and prepend 0
dZS             % sign of difference between consecutive elements. Gives -1, 0, 1
49+c            % convert to a string of '0','1','2' 
'21*?0'XX       % use (lazy) regular expression to detect peaks: '20' or '210' or '2110'...
n               % number of matches. Implicity print

2

Mathematica, 55 39 36 35 byte

Length@FindPeaks[#&@@@Split@#,0,0]&

Ora funziona su tutti i casi di test!


Freddo! Ma FindPeaks [#, 0,0, -∞] è necessario, altrimenti fallisce per l'ultimo caso di test.
njpipeorgan,

Ultimo / @ salva un byte. E l'ultimo ", 0" potrebbe non essere necessario?
njpipeorgan,

Lo stesso trucco per te: Last/@->#&@@@
Martin Ender,


1

JavaScript ES6, 96 94 byte

t=>(a=t.filter((x,i)=>x!=t[i-1])).filter((x,i)=>(x>(b=a[i-1])||!b)&&(x>(c=a[i+1])||!c)).length

Principio: comprimere gli altipiani in singoli picchi, trovare i pick che sono definiti come più alti sia degli elementi successivi che di quelli precedenti.

Accetta input come un array.

demo:

f=t=>
(a=t.filter((x,i)=>x!=t[i-1]))    //collapse every plateau into the pick
    .filter((x,i)=>
       (x>(b=a[i-1])||!b)&&(x>(c=a[i+1])||!c)    //leave only those values which are greater than the succeeding and preceding ones
    ).length

document.write(
  f([])+"<br>"+
  f([1, 1, 1])+"<br>"+
  f([1, 2, 2, 3, 4, 3, 5, 3, 2, 1, 2, 3, 3, 3, 2, 2, 1, 3])+"<br>"+
  f([1])+"<br>"+
  f([1, 1])+"<br>"+
  f([2, 2, 2, 2, 2])+"<br>"+
  f([90])+"<br>"+
  f([2, 1, 2])+"<br>"+
  f([5, 2, 5, 2, 5])+"<br>"+
  f([2, 5, 2, 5, 2, 5, 2])+"<br>"+
  f([1, 2, 3, 4])+"<br>"+
  f([1, 2, 3, 4, 1, 2])+"<br>"+
  f([1, 3, 5, 3, 1])+"<br>"+
  f([7, 4, 2, 1, 2, 3, 7])+"<br>"+
  f([7, 4, 2, 1, 2, 1, 2, 3, 7])+"<br>"+
  f([1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2])+"<br>"+
  f([1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1])+"<br>"+
  f([2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2])+"<br>"+
  f([1, 3, 3, 3, 1, 3, 3, 1, 3, 1, 3, 3, 3, 3, 1])+"<br>"+
  f([12, 1, 2, 1, 2, 3, 3, 3, 2, 4, 4, 4, 1, 5, 5, 4, 7, 9])+"<br>"+
  f([87, 356, 37673, 3676, 386, 909, 909, 909, 909, 454, 909, 909])+"<br>"+
  f([87, 356, 37673, 3676, 386, 909, 909, 909, 909, 454, 909, 908, 909])
)


1

ES6, 50 48 byte

m=>m.map(h=>{f=h>p?c+=!f:f&&h==p;p=h},p=c=f=0)|c

Salvato 2 byte grazie a @ user81655.

Ungolfed:

function peaks(mountains) {
    var previous = 0;
    var count = 0;
    var plateau = false;
    for (var height of mountains) {
        if (height > previous) {
            if (!plateau) count++;
            plateau = true;
        } else if (height != previous) {
            plateau = false;
        }
    }
    return count;
}

@ user81655 Grazie per aver attirato la mia attenzione su quella sottigliezza. (Non l'ho mai usato .map()|prima.)
Neil

1

MATL, 23

Dato che dobbiamo usare gli esolang basati su stack per essere competitivi, ho reimplementato la mia Julia soluzione in MATL.

0i0hhdtg)t5L)0>w6L)0<*s

Premere 0, inserire 0, concatenare due volte.0i0hh=>x = [0, input(''), 0]

Differenziare. d=>x = diff(x)

Duplica t, converti uno in booleano e usalo per indicizzare l'altro.tg)=>x=x(x!=0)

Duplica di nuovo. t

Primo: [1,G])0> =>y1 = x(1:end-1)>0

Scambio. w

Secondo: [2,0])0< =>y2 = x(2:end)<0

Logica e, contare i valori di verità. *s=>sum(y1 & y2)


O potresti Pyth, un linguaggio golfistico procedurale / funzionale!
Isaacg,

OK, MATLAB è MATLAB per il golf, ma MATLAB batte MATL.
Utente generico

Molto bella! Alcuni consigli: [1,G]-> 5Lsalva 3 byte. [2,0]-> 6Lsalva 3 byte
Luis Mendo il


@Rainer Sto pensando di rimuovere and( &) da MATL (e lo stesso per or). Può sempre essere sostituito da *o, e spesso solo *, come in questo caso. Cosa pensi? In questo modo i personaggi &e |potrebbero essere utilizzati per altre funzioni in futuro.
Luis Mendo,

1

Japt, 19 byte

È stato più facile di quanto pensassi, ma l'inizio è leggermente dispendioso a causa di un bug.

Uu0;Up0 ä< ä> f_} l

Provalo online!

Come funziona

Uu0;Up0 ä< ä> f_} l  // Implicit: U = input
Uu0;Up0              // Add 0 to the beginning and end of U. If this isn't done, the algorithm fails on peaks at the end.
        ä<           // Compare each pair of items, returning true if the first is less than the second, false otherwise.
                     // This leaves us with a list e.g. [true, false, false, true, false].
           ä>        // Repeat the above process, but with greater-than instead of less-than.
                     // JS compares true as greater than false, so this returns a list filled with false, with true wherever there is a peak.
              f_} l  // Filter out the falsy items and return the length.

Versione non competitiva, 15 byte

Uu0 p0 ä< ä> è_

Oggi, ho aggiunto la èfunzione, che è comef ma restituisce il numero di partite anziché le partite stesse. Ho anche risolto un bug Array.uche restituiva la lunghezza dell'array anziché l'array stesso.

Provalo online!


1

05AB1E , 9 byte

Ô0.ø¥0‹ÔO

Provalo online!

Spiegazione:

Ô0.ø¥0‹ÔO      Full program
Ô              Uniquify (= remove plateaus)
 0.ø           Surround with zeros
    ¥          Push deltas
     0‹        Test each element if lower than 0
               --- we now have a list with 0's (= going uphill) and 
                   1's (going downhill). Since we removed plateaus, all
                   we have to do now is to count the number of ramps
                   going downhill
       Ô       Uniquify (reduce ramps to length 1)
        O      Total sum of the list


0

GolfScript, 35

~0+0\{.@=!},+:a,2-,{a\>3<.$2=?1=},,

Test online

Rimuove sostanzialmente i duplicati, aggiunge uno 0 ad entrambe le estremità e controlla quante triple hanno un massimo al centro.


0

Java 8, 141 byte

l->{int r=0,i=1,t;for(l.add(0,0),l.add(0);i<l.size()-1;r+=t>l.get(i-1)&t>l.get(++i)?1:0)for(;(t=l.get(i))==l.get(i+1);)l.remove(i);return r;}

Probabilmente si può giocare a golf utilizzando un approccio diverso o un array come input anziché Elenco.

Spiegazione:

Provalo qui.

l->{                     // Method with ArrayList<Integer> parameter and int return-type
  int r=0,               //  Result-integer
      i=1,               //  Index-integer
      t;                 //  Temp integer
  for(l.add(0,0),        //  Add a 0 at the start of the list
      l.add(0);          //  Add a 0 at the end of the list
      i<l.size()-1;      //  Loop (1) from index 1 through length-1 (0-indexed)
      r+=                //    After every iteration, raise the result-integer by:
         t>l.get(i-1)    //     If the current item is larger than the previous
         &t>l.get(++i)?  //     and larger than the next:
          1              //      Increase `r` by 1
         :               //     Else:
          0)             //      `r` remains the same
    for(;(t=l.get(i))==l.get(i+1);
                         //   Inner loop (2) as long as there are two adjacent equal items
      l.remove(i)        //    And remove one of those two equal integers
    );                   //   End of inner loop (2)
                         //  End of loop (1) (implicit / single-line body)
  return r;              //  Return the result-integer
}                        // End of method
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.