我的山脉有几座山峰?


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是的,可能是
卡尔文的爱好

我们可以将输入作为数组而不是字符串吗?
nicael

@nicael是的,任何合理的选择
卡尔文的爱好

Answers:


2

Pyth,18个字节

su_>VGtG2eMr++ZQZ8

基于@PeterTaylor的重复大于解,但有所不同。

++ZQZ:在两边都加零。

eMr ... 8:删除重复项。

u ... 2 ...:两次应用以下内容:

>VGTG:将每对数字映射为它们是否按降序排列。

_:反过来。

输出中的1对应1, 0于先前步骤中的a,a < b > c由于反向,其对应于输入中的步骤。

s:总和(和打印)


10

CJam(32 26 24 21字节)

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

预期的输入是用空格分隔的数字。

在线演示 ; 完整的测试套件1每个测试用例的预期输出)。

感谢Martin通知我,当前版本的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)

测试


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              

真好 与众不同的是,一个端口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)))

垫,区分: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,因此我们可以假设它们大于零,因此可以使用nnz代替来节省2个字节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

这是我的第一个代码高尔夫球,因此可能会有一些地方可以减少使用,特别是其中的d=((n==p)&d)+(n>p)一部分。但是它适用于所有测试用例


那些不是78字节吗?
乔纳森·弗雷希

3

Mathematica,42 36 33 32字节

感谢MartinBüttner节省了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 *)

我发现我的答案您的答案有很大不同,可以发表另一个答案
LegionMammal978 '16

@ LegionMammal978输入{1}的结果为1,如预期的那样。
njpipeorgan


@ LegionMammal978这很棘手。我没有找到解决方案。
njpipeorgan

我更新的解决方案只是使“高原”趋于平坦。
LegionMammal978 '16


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

现在适用于所有测试用例!


凉!但是需要FindPeaks [#,0,0,-∞],否则对于最后一个测试用例将失败。
njpipeorgan

Last / @保存一个字节。而最后一个“,0”可能是不必要的?
njpipeorgan

同样的技巧给您:Last/@->#&@@@
Martin Ender


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


1

ES6,50 48个字节

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

@ user81655节省了2个字节。

取消高尔夫:

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()|。)
Neil 2016年

1

MATL,23岁

由于我们需要使用基于堆栈的esolang来提高竞争力,因此我在MATL中重新实现了Julia解决方案。

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

推送0,输入0,串联两次。0i0hh=>x = [0, input(''), 0]

区分。d=>x = diff(x)

Duplicate t,将其中一个转换为boolean并使用它索引另一个。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,一种程序/功能性高尔夫语言!
isaacg '16

好的,MATL是打高尔夫球的MATLAB,但是MATLAB击败了MATL。
通用用户

非常好!一些提示:[1,G]-> 5L保存3个字节。[2,0]-> 6L保存3个字节
路易斯·门多


@Rainer我正在考虑从MATL 中删除and&)(与相同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会返回数组的长度而不是数组本身。

在线尝试!


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


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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.