实现Thanos排序算法


93

排序算法如下所示:

当列表未排序时,捕捉所有项目的一半(将其从列表中删除)。继续,直到列表已排序或仅剩余一项(默认情况下已排序)。这种分类算法可能会根据实现方式给出不同的结果。

物品清除程序由实施决定,但是经过一遍物品清除程序后,清单的长度应为以前的一半。您的算法可能决定删除列表的前半部分或列表,后半部分,所有奇数项,所有偶数项,一次删除一次,直到列表的长度减半,或者未提及任何内容。

输入列表可以包含任意数量的项目(在某种程度上,我们可以说最多1000个项目),而不仅仅是2 ^ n个项目的完全可分割的列表。如果列表是奇数(硬编码或在运行时随机决定),则必须删除(n + 1)/ 2或(n-1)/ 2个项目。自己决定:如果宇宙中包含奇异数量的生物,Thanos会做什么?

如果没有任何项目小于任何先前的项目,则对列表进行排序。输入中可能会出现重复,输出中可能会出现重复。

您的程序应接收一个整数数组(通过stdin或作为参数,可以是单个项目或一个数组参数),然后返回已排序的数组(或将其打印到stdout)。

例子:

// A sorted list remains sorted
[1, 2, 3, 4, 5] -> [1, 2, 3, 4, 5]

// A list with duplicates may keep duplicates in the result
[1, 2, 3, 4, 3] -> [1, 3, 3] // Removing every second item
[1, 2, 3, 4, 3] -> [3, 4, 3] -> [4, 3] -> [3] // Removing the first half
[1, 2, 3, 4, 3] -> [1, 2] // Removing the last half

[1, 2, 4, 3, 5] 可能给出不同的结果:

// Removing every second item:
[1, 2, 4, 3, 5] -> [1, 4, 5]

要么:

// Removing the first half of the list
[1, 2, 4, 3, 5] -> [3, 5] // With (n+1)/2 items removed
[1, 2, 4, 3, 5] -> [4, 3, 5] -> [3, 5] // With (n-1)/2 items removed

要么:

// Removing the last half of the list
[1, 2, 4, 3, 5] -> [1, 2] // With (n+1)/2 items removed
[1, 2, 4, 3, 5] -> [1, 2, 4] // With (n-1)/2 items removed

要么:

// Taking random items away until half (in this case (n-1)/2) of the items remain
[1, 2, 4, 3, 5] -> [1, 4, 3] -> [4, 3] -> [4]

拥有一个实际上需要针对多个不同捕捉算法的多个捕捉的测试用例将非常有帮助。
不相关的字符串

22
我们不需要排序并消除一半的答案吗?
Sumner18

4
建议的测试用例:[9, 1, 1, 1, 1]。我自己的算法在此输入上失败
Conor O'Brien

Answers:





12

Brachylog(v2),6个字节

≤₁|ḍt↰

在线尝试!

这是函数提交。与往常一样,从左侧输入,在右侧输出。(TIO链接使用命令行参数,该参数自动将功能包装到完整程序中,以便您可以实际查看它。)

说明

≤₁|ḍt↰
≤₁       Assert that {the input} is sorted {and output it}
  |      Handler for exceptions (e.g. assertion failures):
   ḍ     Split the list into two halves (as evenly as possible)
    t    Take the last (i.e. second) half
     ↰   Recurse {and output the result of the recursion}

奖金回合

≤₁|⊇ᵇlᵍḍhtṛ↰

在线尝试!

捕捉是随机的,不是吗?这是该程序的一个版本,该版本随机选择幸存的元素(同时确保每个回合中有一半幸存)。

≤₁|⊇ᵇlᵍḍhtṛ↰
≤₁            Assert that {the input} is sorted {and output it}
  |           Handler for exceptions (e.g. assertion failures):
   ⊇ᵇ         Find all subsets of the input (preserving order)
     lᵍ       Group them by length
       ḍht    Find the group with median length:
         t      last element of
        h       first
       ḍ        half (split so that the first half is larger)
          ṛ   Pick a random subset from that group
           ↰  Recurse

这将是,如果我们可以重新排列元素,而短,但whyever将一个排序算法想做


12
每个无穷大石头一个字节。
djechlin

@djechlin无穷大字节是为什么您必须追求头部,尤其是颌骨的原因。
大鸭

10

Perl 6,30个字节

$!={[<=]($_)??$_!!.[^*/2].&$!}

在线尝试!

递归函数,它将删除列表的后半部分,直到列表被排序为止。

说明:

$!={                         }    # Assign the function to $!
    [<=]($_)??                    # If the input is sorted
              $_                  # Return the input
                !!                # Else
                  .[^*/2]         # Take the first half of the list (rounding up)
                         .&$!     # And apply the function again


8

Java 10,106 97字节

L->{for(;;L=L.subList(0,L.size()/2)){int p=1<<31,f=1;for(int i:L)f=p>(p=i)?0:f;if(f>0)return L;}}

-9个字节,感谢@OlivierGrégoire

在线尝试。

n+12

说明:

L->{               // Method with Integer-list as both parameter and return-type
  for(;;           //  Loop indefinitely:
      L=L.subList(0,L.size()/2)){
                   //    After every iteration: only leave halve the numbers in the list
    int p=1<<31,   //   Previous integer, starting at -2147483648
        f=1;       //   Flag-integer, starting at 1
    for(int i:L)   //   Inner loop over the integer in the list:
      f=p>(p=i)?   //    If `a>b` in a pair of integers `a,b`:
         0         //     Set the flag to 0
        :          //    Else (`a<=b`):
         f;        //     Leave the flag the same
    if(f>0)        //   If the flag is still 1 after the loop:
      return L;}}  //    Return the list as result

n->{for(;n.reduce((1<<31)+0d,(a,b)->a==.5|b<a?.5:b)==.5;n=n.skip(n.count()/2));return n;} 使用流更短,但我无法弄清楚java.lang.IllegalStateException: stream has already been operated upon or closed返回流后如何避免错误
Ignorance的实施例

@EmbodimentofIgnorance的发生是因为这reduce是关闭流的终端操作。您将永远无法reduce在同一流上拨打两次电话。不过,您可以创建一个新的流。
OlivierGrégoire


@OlivierGrégoire现在,该顺序看起来如此简单,以至于我可以看到它。.有时候,我需要从另一个角度看一下最初看来很明显的其他对象。:) 谢谢!
凯文·克鲁伊森

1
不用担心,这并不明显:我努力到达那里。在找到一个版本之前,我测试了至少10个版本;)
OlivierGrégoire


7

JavaScript(ES6), 49 个48字节

@tsh节省了1个字节

删除每个第二个元素。

f=a=>a.some(p=c=>p>(p=c))?f(a.filter(_=>a^=1)):a

在线尝试!


p++&1->a^=1
tsh


6

05AB1E8 7 字节

[Ð{Q#ιн

-1个字节感谢@Emigna

n12

在线尝试验证更多测试用例(或针对每次迭代逐步验证那些测试用例)。

@Grimy替代7 字节

ΔÐ{Ê>äн

n2n12

在线尝试验证更多测试用例(或针对每次迭代逐步验证那些测试用例)。

说明:

[        # Start an infinite loop:
 Ð       #  Triplicate the list (which is the implicit input-list in the first iteration)
  {Q     #  Sort a copy, and check if they are equal
    #    #   If it is: Stop the infinite loop (and output the result implicitly)
  ι      #  Uninterweave: halve the list into two parts; first containing all even-indexed
         #  items, second containing all odd-indexed items (0-indexed)
         #   i.e. [4,5,2,8,1] → [[4,2,1],[5,8]]
   н     #  And only leave the first part

Δ        # Loop until the result no longer changes:
 Ð       #  Triplicate the list (which is the implicit input-list in the first iteration)
       #  Sort a copy, and check if they are NOT equal (1 if truthy; 0 if falsey)
    >    #  Increase this by 1 (so 1 if the list is sorted; 2 if it isn't sorted)
     ä   #  Split the list in that many parts
      н  #  And only leave the first part
         # (and output the result implicitly after it no longer changes)

3
如果切换到保留其他所有元素策略ι则可以使用代替。
Emigna

1
备选方案7使用“删除后半部分”策略:ΔÐ{Ê>äн
肮脏的

@Grimy这也是一种非常好的方法。我应该将其添加到我的帖子中吗(当然要为您评分),还是要将其作为单独的答案发布?
凯文·克鲁伊森

随时添加。
肮脏的

6

TI-BASIC(TI-84),47 42 45 44字节

-1个字节感谢@SolomonUcko!

Ans→L1:Ans→L2:SortA(L1:While max(L1≠Ans:iPart(.5dim(Ans→dim(L2:L2→L1:SortA(L1:End:Ans

输入列表在中Ans
输出已输入,Ans并且已隐式输出。

说明:

Ans→L1                  ;store the input into two lists
Ans→L2
SortA(L1                ;sort the first list
                        ; two lists are needed because "SortA(" edits the list it sorts
While max(L1≠Ans        ;loop until both lists are strictly equal
iPart(.5dim(Ans→dim(L2  ;remove the latter half of the second list
                        ; removes (n+1)/2 elements if list has an odd length
L2→L1                   ;store the new list into the first list (updates "Ans")
SortA(L1                ;sort the first list
End
Ans                     ;implicitly output the list when the loop ends

注意: TI-BASIC是一种标记化语言。字符数不等于字节数。


我想你可以替换not(min(L1=Ans使用max(L1≠Ans,以节省一个字节。
所罗门·乌科



3

八度,49字节

l=input('');while(~issorted(l))l=l(1:2:end);end;l

在线尝试!这是一个无聊越多越好的旅程。请注意下面两个更有趣的条目:

50字节

function l=q(l)if(~issorted(l))l=q(l(1:2:end));end

在线尝试!除了无趣的命令式解决方案,我们还可以为一个额外的字节做一个递归解决方案。

53个字节

f(f=@(g)@(l){l,@()g(g)(l(1:2:end))}{2-issorted(l)}())

在线尝试!是的 一个递归的匿名函数,这要感谢@ceilingcat 在我的问题上的出色回答。通过在参数列表中定义自身来返回递归匿名函数的匿名函数。我喜欢匿名函数。嗯


2

MATL,11个字节

tv`1L)ttS-a

在线尝试!

这是通过删除第二个项目来实现的。

说明

t      % Take a row vector as input (implicit). Duplicate
v      % Vertically concatenate the two copies of the row vector. When read with
       % linear indexing (down, then across), this effectively repeats each entry
`      % Do...while
  1L)  %   Keep only odd-indexed entries (1-based, linear indexing)
  t    %   Duplicate. This will leave a copy for the next iteration
  tS   %   Duplicate, sort
  -a   %   True if the two arrays differ in any entry
       % End (implicit). A new iteration starts if the top of the stack is true
       % Display (implicit). Prints the array that is left on the stack

2
初始排序清单损坏:[1、2、3、4、5]应保留为[1、2、3、4、5]
Falco

@Falco谢谢!已更正
Luis Mendo

2

Japt,10字节

eUñ)?U:ßUë

试试吧

eUñ)?U:ßUë     :Implicit input of array U
e              :Compare equality with
 Uñ            :  U sorted
   )           :End compare
    ?U:        :If true then return U else
       ß       :Run the programme again with input
        Uë     :  Every second element of U


2

水晶,58字节

带有Array#sort58个字节):

->(a : Array(Int32)){while a!=a.sort;a.pop a.size/2;end;a}

在线尝试!

不带Array#sort101个字节):

->(a : Array(Int32)){while a.map_with_index{|e,i|e>a.fetch i+1,Int32::MAX}.any?;a.pop a.size/2;end;a}

在线尝试!


2

外壳6 5字节

Zgarb节省了1个字节

ΩΛ<Ċ2

在线尝试!

说明

ΩΛ<Ċ2
Ω         Repeat until
 Λ<         all adjacent pairs are sorted (which means the list is sorted)
   Ċ2         drop every second element from the list

这是11个字节,不是6个字节。› echo -n“ΩΛ<(←½” | wc --bytes 11
Mike Holler


@MikeHoller和许多其他高尔夫语言一样,Husk使用自定义代码页,以便能够访问更多不同的角色:github.com/barbuz/Husk/wiki/Codepage
Leo

谢谢,我今天学到了一些东西:)
Mike Holler

1
使用Ċ2而不是(←½保存一个字节。
Zgarb

2

盖亚9 8字节

eo₌⟨2%⟩↻

在线尝试!

说明:

e		| eval input as a list
       ↻	| until
 o		| the list is sorted
  ₌		| push additional copy
   ⟨2%⟩  	| and take every 2nd element


2

C ++(gcc),103字节

我无法发表评论,但是我通过减少包含并使用auto改进了movatica的版本。

-2字节:ceilingcat
-2字节:仅ASCII

#include<regex>
auto f(auto l){while(!std::is_sorted(l.begin(),l.end()))l.resize(l.size()/2);return l;}

在线尝试!


1
有什么原因不能仅仅使用l.size()/2
仅ASCII格式的

是的,它不能这样工作:)
peterzuger

1
你什么意思?返回大小列表,(n+1)/2(n-1)/2均有效。嗯......
仅ASCII格式的

哦,哎呀,没有看到谢谢
peterzuger

1

VDM-SL,99个字节

f(i)==if forall x in set inds i&x=1or i(x-1)<=i(x) then i else f([i(y)|y in set inds i&y mod 2=0]) 

以前从未在vdm中提交过,因此不确定特定于语言的规则。所以我已经提交了一个函数定义,该函数接受a seq of int并返回aseq of int

完整的程序可能如下所示:

functions
f:seq of int +>seq of int
f(i)==if forall x in set inds i&x=1or i(x-1)<=i(x) then i else f([i(y)|y in set inds i&y mod 2=0]) 

1

Pyth,10个字节

.W!SIHhc2Z

在这里在线尝试。这将删除每次迭代的后半部分,向下取整。要对其进行更改以删除前半部分(四舍五入),请将更改he

.W!SIHhc2ZQ   Q=eval(input())
              Trailing Q inferred
  !SIH        Condition function - input variable is H
   SIH          Is H invariant under sorting?
  !             Logical not
      hc2Z    Iteration function - input variable is Z
       c2Z      Split Z into 2 halves, breaking ties to the left
      h         Take the first half
.W        Q   With initial value Q, execute iteration function while condition function is true

列表中的其他所有元素都比较短。替换hc%。这也使您可以删除结尾的lambda变量,Z并让Pyth隐式填充它,总共节省了2个字节。
hakr14

1

C ++(GCC) 139个 137 116字节

-2字节thanx到ceilingcat,-21字节thanx到PeterZuger

#include<regex>
auto f(std::vector<int>l){while(!std::is_sorted(l.begin(),l.end()))l.resize(-~l.size()/2);return l;}

将向量的大小调整到其前半部分,直到将其排序为止。

在线尝试!


1
要求将导入内容包括在字节数中,因此您必须添加includes
无知的体现

谢谢,我加他们。
movatica

1

K(oK)22 20字节

解:

{(*2 0N#x;x)x~x@<x}/

在线尝试!

遍历输入直到被排序为止。如果未排序,则取前n / 2个项目。

{(*2 0N#x;x)x~x@<x}/ / the solution
{                 }/ / lambda that iterates
                <x   / indices that sort x ascending (<)
              x@     / apply (@) these indices back to x
            x~       / matches (~) x? returns 0 or 1
 (       ; )         / 2-item list which we index into
          x          / original input (ie if list was sorted)
       #x            / reshape (#) x
   2 0N              / as 2 rows
  *                  / take the first one      

编辑:

  • -2个字节,感谢ngn

1
(.5*#x)#x->*2 0N#x
ngn

我考虑过做,2 0N但是假设这样做会更长(未经测试),谢谢!
6


0

视网膜,38字节

\d+
*
/(_+),(?!\1)/+`,_+(,?)
$1
_+
$.&

在线尝试!以逗号分隔的数字。说明:

\d+
*

转换为一元。

/(_+),(?!\1)/+`

在列表未排序时重复...

,_+(,?)
$1

...删除每个偶数元素。

_+
$.&

转换为十进制。


0

C(gcc),66个字节

每次迭代(n/2+1如果长度为奇数,则为元素)从列表的后半部分开始。

在线尝试!

将输入作为指向数组开头的指针,int后跟数组的长度。通过返回数组的新长度(就地排序)进行输出。

t(a,n,i)int*a;{l:for(i=0;i<n-1;)if(a[i]>a[++i]){n/=2;goto l;}a=n;}

非高尔夫版本:

t(a, n, i) int *a; { // take input as a pointer to an array of int, followed by its length; declare a loop variable i
  l: // jump label, will be goto'ed after each snap
  for(i = 0; i < n - 1; ) { // go through the whole array …
    if(a[i] > a[++i]) { // … if two elements are in the wrong order …
      n /= 2; // … snap off the second half …
      goto l; // … and start over
    }
  }
  a = n; // implicitly return the new length
}

建议~i+n而不是i<n-1
ceilingcat
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.