Сколько пиков в моей горной цепи?

27

Список положительных целых чисел можно представить в виде квантованного горного хребта, где каждая запись списка представляет высоту одного вертикального участка гор.

Например, список

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

может стать ассортиментом

      x
    x x      
   xxxxx   xxx   x
 xxxxxxxx xxxxxx x
xxxxxxxxxxxxxxxxxx

(Менее поэтические люди могли бы назвать это гистограммой, но я отвлекся.)

Вопрос в этой задаче: сколько пиков в горном массиве какого-то произвольного списка? По сути, сколько локальных максимумов в списке?

Пик определяется как непрерывный участок одного или нескольких столбцов горного хребта, которые все равны по высоте, где столбцы непосредственно слева и справа имеют меньшую высоту.

Легко увидеть, что в примере есть четыре пика в этих скобках:

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

Обратите внимание, как участок (3, 3, 3)плато считается пиком, потому что это непрерывный набор столбцов, равных по высоте, выше, чем его соседние столбцы.

Последнее также (3)считается пиком, потому что для целей этой задачи мы определим левого соседа самого левого столбца и правого соседа самого правого столбца равными нулю высоты.

Это означает , что список только с одним значением, например 1, 1, 1, может быть интерпретирован как 0, 1, 1, 1, 0и , таким образом , имеет один пик, а не никто: 0, (1, 1, 1), 0.

Единственный список с нулевыми пиками - это пустой список.

Вызов

Напишите функцию или программу, которая принимает произвольный список натуральных чисел и печатает или возвращает количество пиков в соответствующей горной цепи.

Самый короткий код в байтах побеждает. Tiebreaker - более ранний пост.

Тестовые случаи

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
Кальвин Хобби
источник
Значит, плато может быть произвольно длинным?
Никель
@nicael Да, это может быть
Увлечения Кэлвина
Можем ли мы принять ввод как массив, а не как строку?
Никель
@nicael Да, что-нибудь разумное
Увлечения Кэлвина

Ответы:

2

Pyth, 18 байт

su_>VGtG2eMr++ZQZ8

На основе @ PeterTaylor повторяется больше, чем решение, но с изюминкой.

++ZQZ: Добавить нули с обеих сторон.

eMr ... 8: Удалить повторы.

u ... 2 ...: Примените следующее дважды:

>VGTG: Сопоставить каждую пару чисел с тем, находятся ли они в порядке убывания.

_И наоборот.

1 на выходе соответствует 1, 0предыдущему шагу, который соответствует a < b > cвходу из-за обращения.

s: Сумма (и печать)

isaacg
источник
10

CJam ( 32 26 24 21 байт)

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

Ожидаемый ввод - разделенные пробелами числа.

Онлайн демо ; полный набор тестов (ожидаемый результат для 1каждого теста).

Спасибо Мартину за сообщение, что текущая версия CJam улучшает один из используемых операторов, сохраняя 2 символа; и для дальнейшего сохранения 3-х символов.

рассечение

Две фазы: дедупликация, затем определение локальных максимумов в каждом наборе из трех.

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 байт

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

объяснение

Принимает массив чисел

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)

Тест

user81655
источник
5

Pyth, 25 23 байта

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

Объяснение:

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              
lirtosiast
источник
Ницца. Необычно, порт в CJam короче: 0q~0]{2ew::-:g0-}2*1-,на 22.
Питер Тейлор
4

Юлия, 66

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

Pad, дифференцируются: y=diff([0;x;0]).
Игнорировать плато y=y[y.!=0].
Граф +до -пересечения нуля: sum((y[1:end-1].>0)&(y[2:end].<0)).

Райнер П.
источник
3

MATLAB, 29 27 байт

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

Анонимная функция, которая находит пики в данных и подсчитывает их количество. 0 добавляется и добавляется к данным, чтобы гарантировать, что пики на самых краях обнаружены в соответствии с вопросом.

Это также будет работать с Octave . Вы можете попробовать онлайн здесь . Просто вставьте приведенный выше код в командную строку, а затем запустите его с ans([1,2,1,3,4,5,6,1])(или любым другим вводом).


Поскольку числа всегда + ve, мы можем предположить, что они больше нуля, поэтому можем сохранить 2 байта, используя nnzвместо numel.

Том Карпентер
источник
3

Python 3, 75 байт

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

Это мой первый Codegolf, поэтому могут быть некоторые места, чтобы сократить его, особенно d=((n==p)&d)+(n>p)часть. Однако это работает на всех тестовых случаях

Кэмерон Аавик
источник
Это не 78 байтов ?
Джонатан Фрех,
3

Mathematica, 42 36 33 32 байта

Спасибо Мартину Бюттнеру за сохранение 1 байта.

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

PeakDetect просто делает почти все!

Тестовые случаи:

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 *)
njpipeorgan
источник
Я считаю, что мой ответ достаточно отличается от вашего, чтобы опубликовать другой.
LegionMammal978
@ LegionMammal978 Результат ввода {1} равен 1, как и ожидалось.
njpipeorgan
Я имею в виду {1, 2, 2, 3, 4, 3, 5, 3, 2, 1, 2, 3, 3, 3, 3, 2, 2, 1, 3}
LegionMammal978
@ LegionMammal978 Это сложно. Я не нашел решения.
njpipeorgan
Мое обновленное решение просто сглаживает "плато".
LegionMammal978
2

MATL , 22 байта

0ih0hdZS49+c'21*?0'XXn

Использует текущую версию языка / компилятора.

пример

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

объяснение

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 байт

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

Теперь работает на всех тестовых случаях!

LegionMammal978
источник
Круто! Но FindPeaks [#, 0,0, -∞] необходим, иначе он завершится неудачно в последнем тесте.
njpipeorgan
Last / @ сохраняет байт. И последний ", 0" может быть ненужным?
njpipeorgan
Тот же трюк для вас: Last/@->#&@@@
Мартин Эндер
2

Retina , 33 31 байт

Спасибо Нейлу за сохранение 2 байта.

\b(1+)(?<!\1,\1)(,\1)*\b(?!,\1)

Попробуйте онлайн!

Принимает ввод как разделенный запятыми унарный список.

Мартин Эндер
источник
\b(1+)(?<!\1 \1)( \1)*\b(?! \1)кажется, чтобы сохранить 2 байта?
Нил
@ Конечно, спасибо! :)
Мартин Эндер
1

JavaScript ES6, 96 94 байта

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

Принцип: разложите плато в одиночные пики, найдите пики, которые определены как выше, чем следующий и предыдущий элементы.

Принимает ввод в виде массива.

Демо-версия:

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

nicael
источник
1

ES6, 50 48 байтов

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

Сохранено 2 байта благодаря @ 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 Спасибо, что обратили мое внимание на эту тонкость. (Я не использовал .map()|раньше.)
Нил
1

МАТЛ, 23

Поскольку нам нужно использовать esolangs на основе стека, чтобы быть конкурентоспособными, я переопределил свое решение Julia в MATL.

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

Нажмите 0, введите 0, объедините дважды. 0i0hh=>x = [0, input(''), 0]

Дифференцировать. d=>x = diff(x)

Дублируйте t, конвертируйте одно в логическое значение и используйте его для индексации другого. tg)=>x=x(x!=0)

Дублируйте снова. t

Первый: [1,G])0>=>y1 = x(1:end-1)>0

Обмен. w

Второе: [2,0])0<=>y2 = x(2:end)<0

Логика и подсчитайте правдивые ценности. *s=>sum(y1 & y2)

Райнер П.
источник
Или вы могли бы, Pyth, процедурный / функциональный язык игры в гольф!
Исаак
ОК, MATL - это MATLAB для игры в гольф, но MATLAB обыгрывает MATL.
Общий пользователь
Очень хорошо! Несколько советов: [1,G]-> 5Lэкономит 3 байта. [2,0]-> 6Lсохраняет 3 байта
Луис Мендо
1
@ GenericUser Больше нет :-) codegolf.stackexchange.com/a/69050/36398
Луис Мендо
@Rainer Я думаю об удалении and( &) из MATL (и то же самое для or). Его всегда можно заменить *o, и часто просто так *, как в этом случае. Что вы думаете? Таким образом, символы &и |могут быть использованы для других функций в будущем.
Луис Мендо
1

Japt, 19 байт

Это было проще, чем я думал, но начало немного расточительно из-за ошибки.

Uu0;Up0 ä< ä> f_} l

Попробуйте онлайн!

Как это работает

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.

Неконкурентная версия, 15 байт

Uu0 p0 ä< ä> è_

Ранее сегодня я добавил èфункцию, которая похожа, fно возвращает количество совпадений, а не сами совпадения. Я также исправил ошибку, при которой Array.uвозвращалась бы длина массива, а не сам массив.

Попробуйте онлайн!

ETHproductions
источник
1

05AB1E , 9 байтов

Ô0.ø¥0‹Ô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
scottinet
источник
1

Желе , 27 байт

ṡ2EÐḟFs2ḣ€1S€ṡ3M€Fċ2
0;⁸;0Ç

Попробуйте онлайн!

Zachary
источник
Желе без ТИО ??? LOL
Кристофер
Это было давным-давно, прежде чем я знал, как связаться с TIO. Я оставлю это для потомков.
Захари
Винт, который я исправляю
Кристофер
> _ <_> _ <_> _ <_> _ <
Захари
0

GolfScript, 35

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

Тест онлайн

В основном удаляет дубликаты, добавляет 0 к обоим концам и проверяет, сколько троек имеет максимум в центре.

летучесть
источник
0

Java 8, 141 байт

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

Вероятно, можно использовать другой подход или использовать массив в качестве входных данных вместо List.

Объяснение:

Попробуй это здесь.

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
Кевин Круйссен
источник