数金字塔


17

您应该编写一个程序或函数,该程序或函数接收一个不同整数的列表作为输入,并输出或返回以下倒置数字金字塔中输入数字的出现次数。

在每个步骤中,从原始列表开始,我们创建一个新的列表,其中包含每对相邻数字的最大值(例如5 1 2 6变为5 2 6)。当列表中只有一个数字时,我们停止。

完整的金字塔5 1 2 6就是

5 1 2 6
 5 2 6 
  5 6  
   6   

结果发生的次数分别3 1 2 45 1 2 6

输入项

  • 无重复的一个或多个整数的列表。(例如1 5 1 6无效。)

输出量

  • 正整数列表。i列表的第th个元素是i金字塔中第th个输入数字的出现次数。

例子

输入=>输出

-5 => 1

8 4 => 2 1

5 9 7 => 1 4 1

1 2 3 9 8 6 7 => 1 2 3 16 3 1 2

6 4 2 1 3 5 => 6 4 2 1 3 5

5 2 9 1 6 0 => 2 1 12 1 4 1

120 5 -60 9 12 1 3 0 1200 => 8 2 1 3 16 1 4 1 9

68 61 92 58 19 84 75 71 46 69 25 56 78 10 89 => 2 1 39 2 1 27 6 5 1 6 1 2 14 1 12

这是代码高尔夫球,因此最短的条目将获胜。

难题:您能O(n*log n)及时解决问题吗?


对于函数提交,我是否必须将它们打印到STDOUT或简单地输出它们?
Optimizer

Answers:


4

Pyth,19个 17字节

m/smmeSb.:QhkUQdQ

查看在线演示或完整的测试套件(示例中的第一个4字节迭代)。

这比幼稚的方法聪明一点。三角形的每个数字都可以表示为的连接子集的最大值Q。在第一行中,它使用长度为1的子集,在三角形的第二行中,使用长度为2的子集,...

说明

m/smmeSb.:QhkUQdQ    implicit: Q = input()
   m         UQ         map each k in [0, 1, 2, ..., len(Q)-1] to:
        .:Qhk              all subsets of Q of length (k + 1)
    meSb                   mapped to their maximum
  s                     join these lists together
m               Q    map each d of Q to:
 /             d        its count in the computed list

为了一点可视化。m.:QhdUQ输入[5, 1, 2, 6]提供了所有可能的子集:

[[[5], [1], [2], [6]], [[5, 1], [1, 2], [2, 6]], [[5, 1, 2], [1, 2, 6]], [[5, 1, 2, 6]]]

mmeSk.:QhdUQ给我它们的每个最大值(正好对应于金字塔中的行):

[[5, 1, 2, 6], [5, 2, 6], [5, 6], [6]]

Pyth,23 22字节

|u&aYGmeSd.:G2QQm/sYdQ

这只是简单的“按提示操作”方法。

查看在线演示或完整的测试套件(示例中的第一个4字节迭代)。

说明

meSd.:G2将每对映射[(G[0], G[1]), (G[1], G[2]), ...]到最大元素。

Y是一个空列表,因此aYG追加GY

u...QQ重复应用这两个功能(len(Q)时间),从每次运行开始G = QG在每次运行后进行更新。

m/sYdQ将输入列表的每个元素映射到它们在展平Y列表中的计数。


您的17字节版本使用的算法与我的算法相同,我想这现在也很幼稚:P
Optimizer

13

Python,81岁

def f(L):
 if L:i=L.index(max(L));L=f(L[:i])+[~i*(i-len(L))]+f(L[i+1:])
 return L

分而治之的解决方案。最大元素M一直沿金字塔向下渗透,将其拆分为的矩形M和两个子金字塔。

* * * M * *
 * * M M *
  * M M M
   M M M
    M M
     M

因此,总体结果是左侧子列表的输出,然后是矩形的区域,接着是右侧子列表的输出。

输入变量将L被重用以存储结果,以便将空列表映射到空列表。

解决方案中的构造在Python中比较罗word。也许某些具有模式匹配的语言可以实现以下伪代码?

def f(L):
 [] -> []
 A+[max(L)]+B -> f(A)+[(len(A)+1)*(len(B)+1)]+f(B)

我可以使用Mathematica的模式匹配来缩短一个字节,但它甚至没有超过现有的Mathematica提交:f@{}=##&@@{};f@{a___,l_,b___}/;l>a~Max~b:={f@{a},Length@{a,0}Length@{b,0},f@{b}}
Martin Ender 2015年

6

CJam,23 22字节

仍在寻找高尔夫选择。

{]_,{)W$ew::e>~}%fe=~}

这是CJam函数(某种)。这期望在堆栈上输入数字,并在堆栈上也返回相应的输出计数。一个例子:

5 1 2 6 {]_,{)W$ew::e>~}%fe=~}~

树叶

3 1 2 4

在堆栈上。

可以确定这不是O(n log n)及时的。

代码扩展

]_                     e# Wrap the input numbers on stack in an array and take a copy
  ,{          }%       e# Take length of the copy and run the loop from 0 to length - 1
    )W$                e# Increment the iterating index and copy the parsed input array
       ew              e# Get overlapping slices of iterating index + 1 size
         ::e>          e# Get maximum from each slice
             ~         e# Unwrap so that there can be finally only 1 level array
                fe=    e# For each of the original array, get the occurrence in this
                       e# final array created by the { ... }%
                   ~   e# Unwrap the count array and leave it on stack

让我们来看一个例子,看看它是如何工作的 5 1 2 6

在第二行,5 1 2 6变为5 2 6因为5, 2 and 6是最大的[5 1], [1 2] and [2 6]分别。在第三排,就变成5 6因为5 and 6有最大的[5 2] and [2 6]分别。这也可以[5 1 2] and [1 2 6]分别写为最大。同样,对于最后一行,6最大为[5 1 2 6]

因此,我们基本上创建了合适的长度切片1,该长度切片是从length的片段开始的,该片段基本上是原始数字,每个原始数字都包裹在一个数组中,最后N到最后一行的长度的一片,其中N输入整数的数量。

在这里在线尝试


3

Mathematica,72个字节

Last/@Tally[Join@@NestList[MapThread[Max,{Most@#,Rest@#}]&,#,Length@#]]&

3

Python,81岁

lambda L:[sum(x==max(L[i:j])for j in range(len(L)+1)for i in range(j))for x in L]

金字塔的每个条目都是其向上圆锥顶部的子列表的最大值。所以,我们生成所有这些子列表,通过间隔索引[i,j]0 < i < j <= len(L)和算多少时间每个元素呈现为最大。

枚举子间隔的更短方法可能会节省字符。对的单索引参数化[i,j]将是一种可行的方法。


1

,56 +1 = 57字节

恐怕与CJam伏都教没有太多竞争。看来我需要更好的算法。与-sflag一起运行以获取以空格分隔的输出。

l:gr:0*,#gg:0*g+1WrFir:{c:r@[a--a]c@($<l@c)}M1,#r++(gi)g

取消评论,并附有评论:

l:g                              l = input from cmdline args
r:0*,#g                          r = current row as a list of indices into l
g:0*g+1                          Repurpose g to store the frequencies
Wr                               Loop until r becomes empty
 Fir:{c:r@[a--a]c@($<l@c)}M1,#r  Redefine r (see below) and loop over each i in it
  ++(gi)                         Increment g[i]
g                                Output g

r通过工作的每次重新定义如下:

{c:r@[a--a]c@($<l@c)}M1,#r
{                   }M1,#r       Map this function to each a from 1 to len(r) - 1:
 c:r@[a--a]                      c is a two-item list containing r[a] and r[a-1]
                l@c              The values of l at the indices contained in c
              $<                 Fold/less-than: true iff l[c[0]] < l[c[1]]
           c@(     )             Return c[0] if the former is greater, c[1] otherwise

1

APL(24)

{+/⍵∘.={⍵≡⍬:⍵⋄⍵,∇2⌈/⍵}⍵}

这是一个需要列表的函数,就像这样;

      {+/⍵∘.={⍵≡⍬:⍵⋄⍵,∇2⌈/⍵}⍵}68 61 92 58 19 84 75 71 46 69 25 56 78 10 89
2 1 39 2 1 27 6 5 1 6 1 2 14 1 12

说明:

  • {...}⍵:对apply应用以下功能:
    • ⍵≡⍬:⍵:如果⍵为空,则返回⍵
    • 2⌈/⍵:生成下一个列表
    • ⍵,∇:返回⍵,然后是将此函数应用于下一个列表的结果
  • ⍵∘.=:将⍵中的每个元素与函数结果中的每个元素进行比较
  • +/:对行求和(表示⍵中的元素)

1

Haskell,78个字节

l=length
f x=[l[b|b<-concat$take(l x)$iterate(zipWith max=<<tail)x,a==b]|a<-x]

用法:f [68,61,92,58,19,84,75,71,46,69,25,56,78,10,89]->[2,1,39,2,1,27,6,5,1,6,1,2,14,1,12]

怎么运行的

zipWith max=<<tail   -- apply 'max' on neighbor elements of a list
iterate (...) x      -- repeatedly apply the above max-thing on the
                     -- input list and build a list of the intermediate
                     -- results
take (l x) ...       -- take the first n elements of the above list
                     -- where n is the length of the input list
concat               -- concatenate into a single list. Now we have
                     -- all elements of the pyramid in a single list.
[ [b|b<-...,a==b] | a<-x]
                     -- for all elements 'a' of the input list make a 
                     -- list of 'b's from the pyramid-list where a==b.
 l                   -- take the length of each of these lists    

1

JavaScript,109个字节

我认为我找到了解决这个问题的有趣方法,但是直到完成后我才意识到代码太久了,无法竞争。哦,好吧,如果有人看到更多的高尔夫潜力,可以随时发布。

f=s=>{t=[];for(i=-1;s.length>++i;){j=k=i;l=r=1;for(;s[--j]<s[i];l++);for(;s[++k]<s[i];r++);t[i]=l*r}return t}

我在这里使用以下公式:

i的出现次数=(小于其左侧i的连续数字的数量+ 1)*(小于小于其右侧i的连续数字的数量+ 1)

这样一来,就不需要实际生成整个金字塔或金字塔的子集。(这就是为什么我最初认为它将在O(n)中运行的原因,但是运气不好,我们仍然需要内部循环。)


1

MATLAB:(266羽)

  • 代码的更正需要更多的字节,以后我将很难减少它。
v=input('');h=numel(v);for i=1:h,f=(v(i)>v(1));l=(v(i)>v(h));for j=h-1:-1:i+1,l=(v(i)>v(j))*(1+l);end,if(i>1),l=l+(v(i)>v(i-1))*l;end;for j=2:i-1,f=(v(i)>v(j))*(1+f);end,if(i<h),f=f+(v(i)>v(i+1))*f;end;s=f+l+1;if(i<h&&i>1),s=s-((v(i)>v(i+1))*(v(i)>v(i-1)));end;s
end

输入

向量必须为[abcd ...]形式

  • 例:

    [2 4 7 11 3]

输出值

模式发生。

s =

 1


s =

 2


s =

 3


s =

 8


s =

 1

说明:

如果[abcd]是输入,则程序将结果ghij计算为

g =(a> b)+(a> b)(a> c)+(a> b)(a> c)*(a> d)=(a> b)(1+(a> c)( 1+(a> c))))

h =(b> a)+(b> c)+(b> a)(b> c)+(b> c)(b> d)+(b> a)(b> c)(b> d )= ...“简化”

i =(c> b)+(c> d)+(c> b)(c> d)+(c> b)(c> a)+(c> d)(c> b)(c> a )= ..

j =(d> c)+(d> c)(d> b)+(d> c)(d> b)*(d> a)= ...


0

J(49)

我想还有一些改进的余地...

[:+/~.="1 0[:;([:i.#)<@:(4 :'(}:>.}.)^:x y')"0 1]
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.