生成霍夫施塔特的人形图序列


16

Gödel,Escher,Bach中,Douglas Hofstadter引入了一个整数序列,该序列通常被称为数字图形序列:

2, 4, 5, 6, 8, 9, 10, 11, 13, 14, 15, 16, 17, 19, 20, 21, 22, 23, 24, 25, ...

作为挑战的一部分,您可能会喜欢自己确定序列的定义,但是,如果您不能或不想弄清楚它的定义,可以在OEIS上找到它作为序列A030124在Wikipedia上找到一个稍微清晰的定义。

编写一个程序或函数,该程序或函数n通过STDIN,ARGV或函数参数给出,n以任何合理的列表格式将序列的第一个数字的列表打印到STDOUT。

这是代码高尔夫,最短的解决方案以字节为单位。

Answers:


6

CJam,38 30 29 21字节

li_3*,2>\{(_pX+:X-}*;

在线尝试。

怎么运行的

li                     " Read an integer N from STDIN.              ";
  _3*,2>               " Push S := [ 2 3 ... (N * 3 - 1) ].         ";
        \{        }*   " Do the following N times:                  ";
          (            " Shift an integer I from S.                 ";
           _p          " Print a copy of I, followed by a linefeed. ";
             X+:X      " Execute X += I. (X is initialized to 1.)   ";
                 -     " Remove X from S.                           ";
                    ;  " Discard S from the stack.                  ";

运行示例

$ cjam <(echo 'li_3*,2>\{(_pX+:X-}*;') <<< 20
2
4
5
6
8
9
10
11
13
14
15
16
17
19
20
21
22
23
24
25

输入口译员的网址时,您已经错过了aditsu的s
Beta Decay

@BetaDecay,然后为什么不编辑对其进行修复;)
Martin Ender

@Martin我认为我没有足够的代表...
Beta Decay

2
@BetaDecay您没有,但是您仍然可以建议它们(如果被接受,甚至可以给您2个代表)。
Martin Ender 2014年

我对打掉代码的另外8个字节感到很聪明。然后,我意识到它现在的功能与历史学家,matsjoyce和彼得·泰勒的回答完全一样……
丹尼斯

6

Haskell,67 61 60 56 55 53个字符

g n=take n$2:4:h
a#(x:s)=[a..x-2]++x#s
h=5#scanl(+)8h

回到第一个算法。

该解决方案通过对序列的起始元素求和来计算补码序列。然后,它将序列计算为补码序列号之间的所有数字。

(#)是计算补码序列之间数字的函数。
h是序列本身。
g是回答问题的功能。

g函数定义为仅从h中获取所需数量的元素。

细微之处:

h实际上是数字图形序列,除了前两个元素。
不是计算补码序列,而是计算每个元素加1的补码序列。
这两个微妙之处在于其中的原因scanl(+)8h(这是补码序列(前两个元素除外)加1的代码)8。它是补体序列的第三个元素,其中添加了1。
计算不丢失前两个元素的原因是因为它们被添加到g2:4:h

例:

>g 50
[2,4,5,6,8,9,10,11,13,14,15,16,17,19,20,21,22,23,24,25,27,28,29,30,31,32,33,34,36,37,38,39,40,41,42,43,44,46,47,48,49,50,51,52,53,54,55,57,58,59]

5

红宝石,54 48

f=->n{x=1
b=*2..n*n
n.times{b-=[x+=p(b.shift)]}}

演示版

编辑:一旦我意识到我不需要在内存中保留完整的补码序列,就可以再打一些。现在,它是这样工作的:我们x用来跟踪补码序列中最大的计算数字,并且b是该序列的候选池。n次,我们输出最小的剩余元素b并将其添加x以计算补码序列中的下一个数字。然后,我们从候选者池中删除这两个数字,因此,我们总是输出尚未添加到任一序列中的最小数字。

Ruby golf窍门:Stabby lambda语法比方法定义短。将输出提供给STDOUT而不是作为返回值的要求启发了我使用事实,即p(x)is 的返回值x,我通常不记得,因为在Anarchy Golf中使用的Ruby版本中不是这种情况。


1
它是如何工作的?
骄傲的haskeller 2014年

1
您可以使用FWIW 2..2*n。我必须使用,n*n因为我做b = [x]^b得很有效,所以我需要最大的元素b大于的最大值x,但是您b -= [x]只需要b包含输出序列的最大可能值即可。
彼得·泰勒

4

GolfScript(24 21字节)

~.3*,1>\{(\(.p@+\|}*;

在线演示

这开始了完全不同的,但最终汇聚成的GolfScript端口histocrat红宝石的解决方案之前,丹尼斯提出了一些建议,这需要一个稍微不同的方向。特别是,将我们识别出的数字打印出来比将它们收集到一个数组中以便最后打印要节省很多;原因是,这意味着我们不必担心堆叠中的3个以上项目。

解剖

~.3*,           # Eval input n, dup, multiply by 3, make list [0 1 ... 3n-1]
1>              # Discard 0, which is part of neither sequence
\{              # Execute n times: stack contains pool of numbers not yet seen
                # in either sequence and the first element of it is the next element of the
                # complement sequence
  (\(           #   Pop two numbers from the start of the pool: stack is
                #     pool[0] pool[2..max] pool[1]
  .p            #   Print pool[1]
  @+            #   Rotate pool[0] to top and add to pool[1]
  \|            #   Place pool[0]+pool[1] at the start of the pool and
                #   (this is the clever bit) remove it from later in the pool
}*
;               # Discard the unused remainder of the pool

如果替换^\-,则可以替换).*3*。这不会节省任何字节,但是会大大减少运行时间和内存使用量。-通过将整数保留在数组顶部,您应该能够节省一个字节。循环将具有相同的字节数,但初始化将缩短一字节。
丹尼斯2014年

2
设置工会的工作要比区别更好:~.3*,1>\{(\(.p@+\|}*;
丹尼斯

3

J-28个字符

以函数n为参数。

($+/\(-.~2+i.)&:>:+/)^:_&2 4

我们将带有n左参数的函数反复运行到其右参数上,直到不产生任何变化为止。开始的参数是列表2 4

在函数本身中,我们将部分和+/\与全部和相加+/,然后将两者都增加&:>:。然后,我们生成从2到比全和(2+i.)多一个的每个整数,并设置减(-.)部分和,从而根据定义留下更长的图形序列。最后,我们将列表缩短或循环扩展到length n

结果就是2 4变成了3 7,这从2..8离开中被消除了2 4 5 6 8。又一轮后,2 4 5 6 8变成3 7 12 18 26变成

2 4 5 6 8 9 10 11 13 14 15 16 17 19 20 21 22 23 24 25 27

通过这种方式,我们反复扩展了图形的序列。该$长度行为只是等待序列将增长到长度不平凡的人物节约的方式n或更高,输出n,当他们停止改变第一值。我们也不必等待很长时间:我们可以从内部动词的四个应用程序中获得多达46336个术语。

k中的相同功能:

  • k2,37个字符: {{x#y@&~_lin[y:1+!1+/y;1+\y]}[x]/2 4}
  • k4,36个字符: {{x#y@&~(y:2+!1+/y)in\:1+\y}[x]/2 4}

2

爪哇- 183 158

这是我有史以来打高尔夫球最多的一次,我为此感到自豪!(尽管它离图表的顶部不远(因为它是Java))

感谢Peter Taylor的建议

class f{public static void main(String[]a){int q=1,m=Byte.valueOf(a[0]),w=2,n[]=new int[m*m*2];for(n[q+=w]=1;m-->0;){System.out.println(w);for(;n[++w]>0;);}}}

更大-

public class f {
    public static void main(String[] a) {
        int q = 1, m = Byte.valueOf(a[0]), w = 2, n[] = new int[m * m * 2];
        for (n[q += w] = 1; m-- > 0;) {
            System.out.println(w);
            for (; n[++w] > 0;)
                ;
        }
    }
}

内部for循环非常令人困惑,但是我认为您可以节省一些字节。Byte.valueOf保存三,并且由于问题未指定输入范围,因此我认为应该可以接受。在循环外部,m仅用于初始化n,因此k++<m可以完全m-->0消除kint[] n可以初始化为int n[]并合并到先前的初始化程序中。n除了拥有其他价值之外1n[...]!=0可能如此n[...]>0。然后,初始化程序可以成为第一个for循环的初始化程序部分。
彼得·泰勒

而且,如果您摆脱u使用而只是使用它++w,则无需设置n[q]n[w]。有一个错误,就是您在nwhen 的末尾运行了m==2,这似乎最好通过初始化来解决n=new int[2*m*m],但我认为它可以减少到157个字节。
彼得·泰勒

我的意思是让初始化程序成为第一个for循环的初始化程序部分是for(int q=1,w=2,m=...,n[]=...;m-->0;){...节省分号。
彼得·泰勒

1

Python 2-77字节


码:

n=input();x=1;b=range(2,n*n)
while n:v=b.pop(0);x+=v;print v;b.remove(x);n-=1

除了输入来自stdin外,其工作方式与@histocrat的解决方案相同。


1

Python 2-68

R=[1]
s=0
n=input()
while n:s+=1+(s+1in R);R+=[R[-1]+s];print s;n-=1

0

果冻,15个字节

SƤŻ‘µṀ‘Rḟ
2dz¡ḣ

在线尝试!

输入6时出现内存错误。

怎么运行的

SƤŻ‘µṀ‘Rḟ  Aux. link (monad). Input: part of the desired sequence
SƤŻ‘       Sum of prefixes, then prepend a zero and increment
           This is a list of numbers to exclude from the next iteration
    µ      Re-focus on the above
     Ṁ‘Rḟ  Create range 1..Max + 1, then remove all elements of the above
           +1 is needed to progress from [2] to [2,4]

2dz¡ḣ  Main link (monad). Input: n, number of terms
2dz¡   Starting from 2, apply aux. link n times
    ḣ  Take n elements from the beginning

更有效的版本,16字节

SƤŻ‘µṀ‘Rḟḣ³
2ÇÐL

在线尝试!

使用这个J答案中的一个想法。每次迭代截断到所需的长度,然后获取固定点。我以为使用S(sum)而不是Ṁ‘(max + 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.