对数组进行重排序


44

挑战

给定一个非空的整数数组,例如:

[5, 2, 7, 6, 4, 1, 3]

首先将其切断成没有任何项目大于前一个的数组(即非升序数组):

[5, 2] [7, 6, 4, 1] [3]

接下来,反转每个数组:

[2, 5] [1, 4, 6, 7] [3]

最后,将它们全部串联在一起:

[2, 5, 1, 4, 6, 7, 3]

这应该是程序输出/函数返回的结果。重复此过程足够的时间,数组将被完全排序。

规则

  • 输入和输出可以通过任何标准方法给出,并且可以采用任何合理的数组格式。
  • 输入数组永远不会为空,但可能包含负数和/或重复项。
  • 每个整数的绝对值将始终小于2 31

测试用例

希望这些能够涵盖所有边缘情况:

[1] -> [1]
[1, 1] -> [1, 1]
[1, 2] -> [1, 2]
[2, 1] -> [1, 2]
[2, 3, 1] -> [2, 1, 3]
[2, 1, 3] -> [1, 2, 3]
[2, 1, 2] -> [1, 2, 2]
[2, 1, 1] -> [1, 1, 2]
[3, 1, 1, 2] -> [1, 1, 3, 2]
[3, 2, 1, 2] -> [1, 2, 3, 2]
[3, 1, 2, 2] -> [1, 3, 2, 2]
[1, 3, 2, 2] -> [1, 2, 2, 3]
[1, 0, 5, -234] -> [0, 1, -234, 5]
[1, 0, 1, 0, 1] -> [0, 1, 0, 1, 1]
[1, 2, 3, 4, 5] -> [1, 2, 3, 4, 5]
[5, 4, 3, 2, 1] -> [1, 2, 3, 4, 5]
[2, 1, 5, 4, 3] -> [1, 2, 3, 4, 5]
[2, 3, 1, 5, 4] -> [2, 1, 3, 4, 5]
[5, 1, 4, 2, 3] -> [1, 5, 2, 4, 3]
[5, 2, 7, 6, 4, 1, 3] -> [2, 5, 1, 4, 6, 7, 3]
[-5, -2, -7, -6, -4, -1, -3] -> [-5, -7, -2, -6, -4, -3, -1]
[14, 5, 3, 8, 15, 7, 4, 19, 12, 0, 2, 18, 6, 11, 13, 1, 17, 16, 10, 9] -> [3, 5, 14, 8, 4, 7, 15, 0, 12, 19, 2, 6, 18, 11, 1, 13, 9, 10, 16, 17]

计分

这是,因此以字节为单位的最短代码获胜。


4
这种排序方法有什么大功能?
mbomb007 '16

1
@ mbomb007我不太了解big-o表示法,但我认为单个迭代是O(n)。将其乘以最坏情况的n次迭代,得到O(n ^ 2)(最坏情况;对于单次迭代,最佳情况是O(n))。
ETHproductions 2016年

1
这听起来对我来说很正确,但是值得指出的是,反转数组不是一个非常有效的操作,所以它很慢O(n^2)
DJMcMayhem

2
@WheatWizard反转数组不需要为数组副本提供空间,而只需为单个元素提供空间。并且是O(n)。当您到达中间位置时,交换第一个和最后一个元素,然后交换第二个和第二个最后一个元素,依此类推。
杰森

反转是O(n),但是反转可以直接建立在算法中(这就是我的JS回答所做的事情);由于每次迭代都会循环遍历数组中的每个项目一次,因此单次迭代为O(n)。(我认为...)
ETHproductions 2016年

Answers:


19

JavaScript(ES6),64字节

f=([n,...a],z=[],q=[n,...z])=>a+a?n<a[0]?[...q,...f(a)]:f(a,q):q

递归FTW!此处使用的基本算法是跟踪数组中当前的非升序运行,并在找到升序元素时“将其返回”。我们以递归方式执行此操作,不断将结果连接起来,直到用完所有项目。通过反向创建每个运行([n,...z]而不是[...z,n]),我们可以免费避免冗长的运行.reverse()

测试片段


您能否解释一下如何将数组解析为第一个参数[n,...a]。什么n啊 那只是数组中的第一项吗?
奥利弗

1
@obarakon正确。n是数组中的第一项,也是数组a的其余部分。您可以在此处找到更多信息。
ETHproductions 2013年

谢谢。那很有帮助。由于您的第一个参数是数组,因此为什么需要包含...a??那样只是为了您可以利用n吗?还有一件事,当您调用时f(a,q),是否q将其设置为参数z
奥利弗(Oliver)

1
@obarakon好,f=([n])=>...只捕获的第一个元素,而f=([n,a])=>...将只捕获在第一n和第二a。做事的另一种方式f=([n,...a])=>,,,f=a=>(n=a.unshift(),...
ETHproductions 2016年

1
并且由于z是函数中的第二个参数,因此在f(a,q)调用时f将其视为z。希望这可以帮助!
ETHproductions 2016年


11

果冻,8字节

Ṁ;<œṗ³UF

在线尝试!

说明:

Ṁ;         Prepend the list [a1, a2… an] with its maximum.
  <        Elementwise compare this with the original list:
           [max(a) < a1, a1 < a2, …, a(n-1) < an, an]
           The first element is always 0.
   œṗ³     Partition the original list (³) at the indices
           of the non-zero values in the working list.
           (The spurious `an` at the end of the left argument,
           resulting from comparing lists of different sizes,
           is ignored by this operation, thankfully.)
      U    Reverse each part.
       F   Flatten.

1
看到您的答案时,我几乎要点击“ 保存编辑” ...干得好。
丹尼斯

@Dennis Heh,所以您添加了Dyalog分区包围,但是APL2分区呢?
2013年

11

JavaScript(ES6),70个字节

当然,这已经被ETHproductions的答案所击败,但这是到目前为止我不使用递归就可以提出的最好的答案

a=>a.map((n,i)=>a[x=[...o,...r=[n,...r]],i+1]>n&&(o=x,r=[]),r=o=[])&&x

注意:初始化ro并使用完全相同的对象r = o = []似乎是一个危险的主意。但这是安全的,因为在第一次迭代时,r立即使用分配了自己的实例(包含的第一个元素ar = [n, ...r]

测试用例


2
不用担心,我喜欢看到不同的方法。打高尔夫球之后,一个人往往
会变

8

MATL,15字节

lidO>vYsGhXSOZ)

输入是列向量,其格式为[5; 2; 7; 6; 4; 1; 3](分号是行分隔符)。

在线尝试!

以输入[5; 2; 7; 6; 4; 1; 3]为例。

说明

l     % Push 1
      % STACK: 1
i     % Push input
      % STACK: 1, [5; 2; 7; 6; 4; 1; 3]
d     % Consecutive differences
      % STACK: 1, [-3; 5; -1; -2; -3; 2]
O>    % Test if greater than 0, element-wise
      % STACK: 1, [0; 1; 0; 0; 0; 1]
v     % Concatenate vertically
      % STACK: [1; 0; 1; 0; 0; 0; 1]
Ys    % Cumulative sum
      % STACK: [1; 1; 2; 2; 2; 2; 3]
G     % Push input again
      % STACK: [1; 1; 2; 2; 2; 2; 3], [5; 2; 7; 6; 4; 1; 3]
h     % Concatenate horizontally
      % STACK: [1 5; 1 2; 2 7; 2 6; 2 4; 2 1; 3 3]
XS    % Sort rows in lexicographical order
      % STACK: [1 2; 1 5; 2 1; 2 4; 2 6; 2 7; 3 3]
OZ)   % Get last column. Implicitly display
      % STACK: [2; 5; 1; 4; 6; 7; 3]

我将您的答案翻译为Octave,为我节省了31个字节!
rahnema16年


5

Python 2,100字节

一场非常糟糕的高尔夫,但是我想发布自己的解决方案(这不仅仅是超越丹尼斯的高尔夫) ...

d=input();L=[];x=0;d+=-~d[-1],
for i in range(1,len(d)):
 if d[i]>d[i-1]:L+=d[x:i][::-1];x=i
print L

测试repl.it!

输入应以Python列表文字的形式给出,例如[5, 3, 4, 2, 6, 1]

基本思想是大量使用Python的切片语法,从数组中切片每个必要的部分,将其反转,然后将其添加到新数组中。


我认为第一行可以d,L,x=input(),[],0;d+=...
丹尼尔(Daniel)

@Dopapp字节数完全相同
FlipTack

4

Pyke,11个 8字节(旧版本

$0m<fm_s

在这里尝试!(适用于最新版本)

$        -     delta(input)
 0m<     -    map(i<0 for i in ^)
    f    -   split_at(input, ^)
     m_  -  map(reverse, ^)
       s - sum(^)

4

视网膜,163字节

是的,我知道这有多可怕。支持零和底片是超级有趣。字节数假定为ISO 8859-1编码。

\d+
$*
(?<=-1*)1
x
-

x,1
x¶1
\b(1+),(1+\1)\b
$1¶$2
,,1
,¶1
x,(¶|$)
x¶¶
(?<=\b\1x+(?=,(x+))),\b
¶
O%$#`.(?=(.*))
$.1
+`¶
,
\bx
-x
(\w+)
$.1
^,
0,
,$
,0
,,
,0,
^$
0

在线尝试

说明:

\d+                         # Convert to unary
$*
(?<=-1*)1                   # Replace negatives with x's instead of 1's
x
-                           # Remove minus sign

x,1                         # Separate if negative before positive
x¶1
\b(1+),(1+\1)\b             # or greater positive follows a positive
$1¶$2
,,1                         # or positive follows a zero
,¶1
x,(¶|$)                     # or zero follows a negative
x¶¶
(?<=\b\1x+(?=,(x+))),\b     # or negative follows a negative of greater magnitude.
¶
O%$#`.(?=(.*))              # Swear at the input, then reverse each line
$.1
+`¶                         # Remove breaks, putting commas back
,
\bx                         # Put the minus signs back
-x
(\w+)                       # Replace unary with length of match (decimal)
$.1
^,                          # Do a bunch of replacements to resurrect lost zeros
0,
,$
,0
,,
,0,
^$
0

4

05AB1E19 18 16 14字节

使用Luis Mendo的排序技巧节省了2个字节

ü‹X¸ì.pO¹)ø{ø¤

在线尝试!

说明

输入示例 [5, 2, 7, 6, 4, 1, 3]

ü‹               # pair-wise less-than
                 # STACK: [0, 1, 0, 0, 0, 1]
  X¸ì            # prepend a 1
                 # STACK: [1, 0, 1, 0, 0, 0, 1]
     .p          # prefixes
       O         # sum
                 # STACK: [1, 1, 2, 2, 2, 2, 3]
        ¹        # push input
                 # STACK: [1, 1, 2, 2, 2, 2, 3], [5, 2, 7, 6, 4, 1, 3]
         )       # wrap stack in list
                 # STACK: [[1, 1, 2, 2, 2, 2, 3], [5, 2, 7, 6, 4, 1, 3]]
          ø      # zip
                 # STACK: [[1, 5], [1, 2], [2, 7], [2, 6], [2, 4], [2, 1], [3, 3]]
           {     # sort
                 # STACK: [[1, 2], [1, 5], [2, 1], [2, 4], [2, 6], [2, 7], [3, 3]]
            ø    # zip
                 # STACK: [[1, 1, 2, 2, 2, 2, 3], [2, 5, 1, 4, 6, 7, 3]]
             ¤   # tail
                 # OUTPUT: [2, 5, 1, 4, 6, 7, 3]

以前的16字节解决方案

Dü‹X¸ì.pO.¡€g£í˜

那些换行符很好地解释了... :-P
Stewie Griffin

@StewieGriffin:是的,我修改了代码并在重新
编写

4

的JavaScript(ECMA 6),121 128 125 119 108个字节

f=a=>{p=a[0],c=[],b=[];for(e of a){e>p&&b.push(c.reverse(c=[]));c.push(p=e)}return[].concat.call([],...b,c)}

Lambda表达式采用单个Array参数a

感谢@ETHproductions帮助我看到我的第一个错误。


真好!我认为您可以return(b+","+c).split`,` 在最后节省一些字节。
ETHproductions 2016年

1
更好的是,您可以使用c.unshift代替c.push来消除反向需求c。完成此操作后,我得到了94个字节
ETHproductions 2016年

3

Ruby,60 55字节

s=->x{x.slice_when{|p,q|p<q}.map{|z|z.reverse}.flatten} 

挑战所要求的几乎是什么。我定义了一个lambda s,它接受一个数组x,并将其切断(切片)成较小的块,其中后面的元素将大于该值。这将返回一个枚举器,我们可以调用map并逆转片段的顺序,然后最终将它们全部与flatten结合在一起,后者按定义的顺序将元素连接到一个数组中。

测验

p s[[1]]===[1]
p s[[1, 1]]===[1, 1]
p s[[1, 2]]===[1, 2]
p s[[2, 1]]===[1, 2]
p s[[2, 3, 1]]===[2, 1, 3]
p s[[2, 1, 3]]===[1, 2, 3]
p s[[2, 1, 2]]===[1, 2, 2]
p s[[2, 1, 1]]===[1, 1, 2]
p s[[3, 1, 1, 2]]===[1, 1, 3, 2]
p s[[3, 2, 1, 2]]===[1, 2, 3, 2]
p s[[3, 1, 2, 2]]===[1, 3, 2, 2]
p s[[1, 3, 2, 2]]===[1, 2, 2, 3]
p s[[1, 0, 5, -234]]===[0, 1, -234, 5]
p s[[1, 0, 1, 0, 1]]===[0, 1, 0, 1, 1]
p s[[1, 2, 3, 4, 5]]===[1, 2, 3, 4, 5]
p s[[5, 4, 3, 2, 1]]===[1, 2, 3, 4, 5]
p s[[2, 1, 5, 4, 3]]===[1, 2, 3, 4, 5]
p s[[2, 3, 1, 5, 4]]===[2, 1, 3, 4, 5]
p s[[5, 1, 4, 2, 3]]===[1, 5, 2, 4, 3]
p s[[5, 2, 7, 6, 4, 1, 3]]===[2, 5, 1, 4, 6, 7, 3]
p s[[-5, -2, -7, -6, -4, -1, -3]]===[-5, -7, -2, -6, -4, -3, -1]
p s[[14, 5, 3, 8, 15, 7, 4, 19, 12, 0, 2, 18, 6, 11, 13, 1, 17, 16, 10, 9]]===[3, 5, 14, 8, 4, 7, 15, 0, 12, 19, 2, 6, 18, 11, 1, 13, 9, 10, 16, 17]

1
:欢迎,漂亮的<S>第一</ S>第二个答案,看看这个codegolf.stackexchange.com/questions/363/...
GB

非常感谢。根据您提供的链接中的建议,将其转换为lambda,并以此方式保存了5个字节。
manonthemat

2

Brachylog,10个字节

~c:{>=r}ac

在线尝试!

说明

~c            Deconcatenate the Input
  :{>=r}a     Each resulting sublist must be non-increasing, and then reverse it
         c    Concatenate

c反向运行Brachylog 时是否一定要先尝试拆分成更少的列表?

@ ais523是的,确实如此。
致命

1

Dyalog APL7个 15 字节

需要⎕ML←3,这在许多系统上都是默认的。*

{∊⌽¨⍵⊂⍨1+⍵-⌊/⍵}

征募(拼合)

⌽¨ 每个反转

⍵⊂⍨ 通过切开其中每个对应元素大于其前任元素的位置对参数进行划分*

1+ 一加

⍵- 减去参数

⌊/⍵ 参数的最小元素


旧的7字节解决方案因非正整数而失败:

需要⎕ML←3,这在许多系统上都是默认的。*

∊⌽¨⊆⍨⎕

招募(拼合)

⌽¨ 每个反转

⊂⍨ 自分区*


* Partition()是一个函数,它会在其对应的左参数大于前一个参数时剪切其右参数。(不幸的是,它仅接受非负整数,零具有特殊含义。)从版本16开始,使用glyph的此功能可在所有系统上⎕ML≠3使用,甚至在所有系统上也可用


1

Haskell,49个字节

(a:b)%l|any(<a)l=l++b%[a]|1<2=b%(a:l)
_%l=l
(%[])

用法示例:(%[]) [5,2,7,6,4,1,3]-> [2,5,1,4,6,7,3]

递归方法。该函数%将输入列表作为第一个参数,并使用一个累加器l,该累加器到目前为止一直跟踪非递增块(以相反的顺序)。当输入列表为空且结果为累加器时,将达到基本情况。如果输入列表不为空,并且第一个元素a不适合当前块(any(<a)l),则返回累加器并将递归调用追加到列表的其余部分,并a作为新的累加器(l++b%[a])。否则,对列表的其余部分进行递归调用,并a在累加器(b%(a:l))之前添加。主函数使用空的累加器进行(%[])调用%



1

R,64字节

cat(unlist(lapply(split(x<-scan(),cumsum(c(F,diff(x)>0))),rev)))

从标准输入读取输入。我们将输入分为向量列表,使用split()该列表需要将输入分组的因子变量。通过取差值为正的逻辑向量的累加和来创建因子。

考虑向量:

x=c(5, 2, 7, 6, 4, 1, 3)

现在考虑差异并F通过运行y=c(F,diff(x)>0)将产生以下逻辑向量:

[1] FALSE FALSE  TRUE FALSE FALSE FALSE  TRUE

取累加和cumsum(y)产生一个向量,其中每个组由一个唯一因子表示,我们可以将其与split函数结合:

[1] 0 0 1 1 1 1 2

使用diffinv而不是的60个字节cumsum
朱塞佩

1

八度,75 44字节

基于@LuisMendo的MATL答案

@(a)sortrows([cumsum([1;diff(a)>0]),a])(:,2)

在线尝试!

上一个答案

@(a)[fliplr(mat2cell(f=fliplr(a),1,diff(find([1,diff(f)<0,numel(a)])))){:}]

在线尝试!

反转数组

f=fliplr(a)

首先采取 f

d = diff(f);

查找下一个元素小于上一个元素的位置

p=find([1,diff(f)<0,numel(a)])

位置的第一差返回每个子数组的长度

len=diff(p)

使用每个子数组的长度将数组mat2cell拆分为嵌套的数组列表

nest = mat2cell(f,1,len);

反转嵌套列表

rev_nest = fliplr(nest) 

展平嵌套列表

[rev_nest{:}]


0

Perl 6、59字节

{map |+«*.[0].reverse,m/:s([(\-?\d+)<?{[>=] $0}>] +)+/[0]}

基于正则表达式的解决方案。
因为这是Sparta Perl!

  • m/ /:对输入数组进行字符串化处理,并对其匹配一个正则表达式。
  • (\-? \d+):匹配一个数字,并将其捕获为$0
  • <?{ [>=] $0 }>:零宽度断言,仅当$0当前子匹配中到目前为止捕获的所有字符都以非升序排列时才匹配。
  • ([ ] +)+:请尽可能重复最后两个步骤,否则开始新的子比赛。
  • map , [0]:迭代子匹配项。
  • |+«*.[0].reverse:对于每个,取与匹配的值列表,将其$0反转,将值强制为数字(),然后将其滑入外部列表(|)。

Perl 6、63个字节

sub f(\a){flat $_,f a[+$_..*]with first {[<=] $_},:end,[\R,] a}

递归列表处理解决方案。
比我希望的要费力。
即使该语言具有许多方便的内置函数,似乎也没有列表分区(例如Ruby slice_when或Haskell的列表分区takeWhile)。


0

堆叠式,非竞争性,34个字节

仍在不断开发这种语言。

{e.b:e b last<}chunkby$revmap flat

论据在于TOS。在这里尝试!

chunkby接受一个函数并收集满足该函数的连续数据数组。该函数是:

{e.b:e b last<}
{e.b:         }  function with arguments [e, <unused>, b]--the element, <the index>, and the
                 chunk being built
     e       <   check if e is less than
       b last    the last element of b

这给出了严格减少的数组。

$revmap基本上是[rev]map将每个项目颠倒。

flat 最后使数组变平。


实际对数组进行排序很有趣:

[{e.b:e b last<}chunkby$revmap flat] @:sortstep
[$sortstep periodloop] @:sort

10:> @arr
arr out
arr shuf @arr
arr out
arr sort out

输出(例如):

(0 1 2 3 4 5 6 7 8 9)
(4 5 1 0 6 7 2 8 9 3)
(0 1 2 3 4 5 6 7 8 9)

0

Python,第151个 139字节

@ Flp.Tkc节省了12个字节!

@ Flp.Tkc附近,更不用说...

def s(l):
 r=[];i=j=0
 while j<len(l)-1:
  if l[j+1]>l[j]:r+=l[i:j+1][::-1],;i=j+1
  j+=1
 r+=l[i:j+1][::-1],;return[i for s in r for i in s]

而不是使用追加,而是使用+= data,结尾逗号隐式构造一个元组,然后将其与列表连接,将数据添加为列表中的最后一个元素。在这种情况下,请r+=l[i:j+1][::-1],
-FlipTack


0

Python 3,191字节

a=[int(i)for i in input().split()]
while a!=sorted(a):
 b=[[]]
 for i,j in enumerate(a):
  if a[i-1]<j:b+=[[j]]
  else:b[-1]+=[j]
 a=[]
 for l in[k[::-1]for k in b]:a+=[k for k in l]
print(a)

我不确定在sorted这里是否允许使用该函数进行检查,但是我想不出一个很好的理由,它使我的字节数减少了约30个字节。


0

Clojure,105个字节

#(filter number?(mapcat reverse(partition-by not(mapcat(fn[[a b]][a(< b a)])(partition 2 1(conj % 1))))))

在连续的数字上划分成对,在它们之间放置truefalse在它们之间,nottrue和上的分区变成falseand false true,反转分区并保留数值。

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.