Quantos picos na minha cordilheira?


27

Uma lista de números inteiros positivos pode ser visualizada como uma cadeia de montanhas quantizada em que cada entrada da lista representa a altura de uma seção vertical das montanhas.

Por exemplo, a lista

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

pode se tornar o intervalo

      x
    x x      
   xxxxx   xxx   x
 xxxxxxxx xxxxxx x
xxxxxxxxxxxxxxxxxx

(Pessoas menos poéticas podem chamar isso de gráfico de barras, mas eu discordo.)

A questão deste desafio é: Quantos picos existem na cordilheira de alguma lista arbitrária? Essencialmente, quantos máximos locais existem na lista?

Um pico é definido como uma seção contígua de uma ou mais colunas da cordilheira, todas iguais em altura, onde as colunas imediatamente à esquerda e à direita têm menor altura.

É fácil dizer visualmente que o exemplo tem quatro picos nesses locais entre parênteses:

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

Observe como a (3, 3, 3)seção do platô conta como um pico, porque é um conjunto contíguo de colunas com altura igual e superior às colunas vizinhas.

O último (3)conta também como pico, porque, para os propósitos deste desafio, definiremos o vizinho esquerdo da coluna mais à esquerda e o vizinho direito da coluna mais à direita como altura zero.

Isto significa que uma lista com apenas um valor, por exemplo 1, 1, 1, pode ser interpretado como 0, 1, 1, 1, 0, e, portanto, tem um pico, não nenhum: 0, (1, 1, 1), 0.

A única lista com picos zero é a lista vazia.

Desafio

Escreva uma função ou programa que obtenha uma lista arbitrária de números inteiros positivos e imprima ou retorne o número de picos na cordilheira correspondente.

O código mais curto em bytes vence. O desempatador é uma publicação anterior.

Casos de teste

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

Então, o platô pode ser arbitrário por muito tempo?
Nicael

@nicael Sim, poderia ser
Calvin's Hobbies

Podemos considerar a entrada como uma matriz, não como uma string?
Nicael

@nicael Sim, qualquer coisa razoável
Calvin's Hobbies

Respostas:


2

Pitão, 18 bytes

su_>VGtG2eMr++ZQZ8

Baseado em @ PeterTaylor repetiu maior que a solução, mas com uma torção.

++ZQZ: Adicione zeros nos dois lados.

eMr ... 8: Remova as repetições.

u ... 2 ...: Aplique o seguinte duas vezes:

>VGTG: Mapeie cada par de números para saber se eles estão em ordem decrescente.

_: E reverter.

Um 1 na saída corresponde a um 1, 0na etapa anterior, que corresponde à a < b > centrada devido à reversão.

s: Soma (e impressão)


10

CJam ( 32 26 24 21 bytes)

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

A entrada esperada é de números separados por espaço.

Demonstração online ; conjunto de testes completo (a saída esperada é um 1caso de teste).

Agradeço a Martin por me informar que a versão atual do CJam aprimora um dos operadores utilizados, economizando 2 caracteres; e para uma economia adicional de 3 caracteres.

Dissecação

Duas fases: desduplicar e, em seguida, identificar o máximo local em cada conjunto de três.

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 bytes

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

Explicação

Toma uma matriz de números

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)

Teste


5

Pitão, 25 23 bytes

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

Explicação:

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              

Agradável. Excepcionalmente, uma porta para CJam é mais curto: 0q~0]{2ew::-:g0-}2*1-,para 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, diferenciar: y=diff([0;x;0]).
Ignorar os planaltos: y=y[y.!=0].
Contagem +de -cruzamentos de zero: sum((y[1:end-1].>0)&(y[2:end].<0)).


3

MATLAB, 29 27 bytes

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

Função anônima que encontra os picos nos dados e conta quantos existem. 0 é anexado e anexado aos dados para garantir que os picos nas extremidades sejam detectados conforme a pergunta.

Isso também funcionará com o Octave . Você pode tentar online aqui . Simplesmente cole o código acima na linha de comando e execute-o com ans([1,2,1,3,4,5,6,1])(ou qualquer outra entrada).


Como os números são sempre + ve, podemos assumir que eles são maiores que zero e, portanto, podemos economizar 2 bytes usando em nnzvez de numel.


3

Python 3, 75 bytes

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

Este é o meu primeiro codegolf, então pode haver alguns lugares para reduzi-lo, especialmente a d=((n==p)&d)+(n>p)parte. No entanto, funciona em todos os casos de teste


Esses não são 78 bytes ?
Jonathan Frech

3

Mathematica, 42 36 33 32 bytes

Agradecemos a Martin Büttner por economizar 1 byte.

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

PeakDetect apenas faz quase tudo!

Casos de teste:

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 *)

Acho que minha resposta é suficientemente diferente da sua para postar outra.
LegionMammal978

@ LegionMammal978 O resultado da entrada {1} é 1, conforme o esperado.
Njpipeorgan

Quero dizer {1, 2, 2, 3, 4, 3, 5, 3, 2, 1, 2, 3, 3, 3, 2, 2, 1, 3}
LegionMammal978

@ LegionMammal978 Isso é complicado. Não encontrei uma solução.
Njpipeorgan 9/01/16

Minha solução atualizada apenas nivela "platôs".
LegionMammal978


2

MATL , 22 bytes

0ih0hdZS49+c'21*?0'XXn

Usa a versão atual do idioma / compilador.

Exemplo

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

Explicação

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 bytes

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

Agora funciona em todos os casos de teste!


Legal! Mas FindPeaks [#, 0,0, -∞] é necessário, caso contrário, falhará no último caso de teste.
Njpipeorgan

Last / @ salva um byte. E o último ", 0" pode ser desnecessário?
Njpipeorgan

O mesmo truque para você: Last/@->#&@@@
Martin Ender


1

JavaScript ES6, 96 94 bytes

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

Princípio: colapsar planaltos em picos únicos, encontre os picos que são definidos como sendo mais altos que os elementos seguintes e anteriores.

Recebe entrada como uma matriz.

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 bytes

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

Economizou 2 bytes graças 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 Obrigado por chamar minha atenção para essa sutileza. (Eu não usei .map()|antes.)
Neil

1

MATL, 23

Como precisamos usar esolangs baseados em pilha para sermos competitivos, reimplementei minha solução Julia em MATL.

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

Empurre 0, insira 0, concatene duas vezes. 0i0hh=>x = [0, input(''), 0]

Distinguir. d=>x = diff(x)

Duplique t, converta um em booleano e use-o para indexar o outro. tg)=>x=x(x!=0)

Duplicar novamente. t

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

Troca. w

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

Lógica e, conte os valores verdadeiros. *s=>sum(y1 & y2)


Ou você pode Pyth, uma linguagem de golfe processual / funcional!
Isaacg

OK, MATL é MATLAB para jogar golfe, mas MATLAB está superando MATL.
Usuário genérico

Muito agradável! Algumas dicas: [1,G]-> 5Lsalva 3 bytes. [2,0]-> 6Lsalva 3 bytes
Luis Mendo


@Rainer Estou pensando em remover and( &) do MATL (e o mesmo para or). Ele sempre pode ser substituído por *o, e geralmente por apenas *, como neste caso. O que você acha? Dessa forma, os personagens &e |podem ser usados ​​para outras funções no futuro.
Luis Mendo

1

Japonês, 19 bytes

Isso foi mais fácil do que eu pensava, mas o começo é um pouco inútil devido a um bug.

Uu0;Up0 ä< ä> f_} l

Experimente online!

Como funciona

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.

Versão não concorrente, 15 bytes

Uu0 p0 ä< ä> è_

Hoje, eu adicionei a èfunção, que é como, fmas retorna o número de correspondências em vez das correspondências em si. Também consertei um bug em Array.uque retornaria o comprimento da matriz em vez da própria matriz.

Experimente online!


1

05AB1E , 9 bytes

Ô0.ø¥0‹ÔO

Experimente online!

Explicação:

Ô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=},,

Teste on-line

Basicamente, remove duplicatas, adiciona 0 a ambas as extremidades e verifica quantos triplos têm um máximo no centro.


0

Java 8, 141 bytes

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;}

Provavelmente, você pode jogar golfe usando uma abordagem diferente ou uma matriz como entrada, em vez de Lista.

Explicação:

Experimente aqui.

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