霍夫施塔特H序列


15

定义

  • a(0) = 0
  • a(n) = n-a(a(a(n-1))) 对于整数 n > 0

任务

给定非负整数n,输出a(n)

测试用例

n     a(n)
0     0
1     1
2     1
3     2
4     3
5     4
6     4
7     5
8     5
9     6
10    7
11    7
12    8
13    9
14    10
15    10
16    11
17    12
18    13
19    13
20    14
10000 6823

参考文献


约霍夫斯塔特序列相关的挑战:123
马丁安德

4
而且我仍然认为您应该参考GEB ...
Martin Ender

1
如何是数论与此有关?
flawr

1
@flawr facepalm 让我再试一次:Gödel,Escher,Bach:永恒的金色辫子
Stig Hemmer

1
@StigHemmer其实捂脸都有自己现在的表情符号:🤦
托比亚斯Kienzler

Answers:


20

Haskell,23 22字节

f 0=0
f n=n-f(f$f$n-1)

只需使用序列的定义。f(f$f$n-1)等同于f (f (f (n-1)))

测试:

main = putStrLn . show $ map f [0..20]
-- => [0,1,1,2,3,4,4,5,5,6,7,7,8,9,10,10,11,12,13,13,14]

感谢Anders Kaseorg的帮助!


(f$f$f$n-1)= f(f$f$n-1)保存一个字节。
Anders Kaseorg '16

9

果冻,8 字节

’ßßßạµṠ¡

在线尝试!验证较小的测试用例

怎么运行的

’ßßßạµṠ¡  Main link. Argument: n

     µṠ¡  Execute the preceding chain sign(n) times.
’         Decrement n, yielding n - 1.
 ßßß      Recursively call the main link thrice.
    ạ     Take the absolute difference of n and the result.

9
果冻解析器能否处理大于10个字节的程序?
steenbergh

9

Mathematica,20个字节

字节计数采用ISO 8859-1(或兼容)编码,并$CharacterEncoding设置为匹配值,例如Windows default WindowsANSI

±0=0
±n_:=n-±±±(n-1)

这定义了一元运算符±


您能解释一下它的作用或作用方式吗?顺便说一句,恭喜10万。
DavidC

1
@DavidC谢谢。:)这只是一个内置运算符,它是未使用函数的简写PlusMinus。有关详细信息,请参见此帖子
Martin Ender

1
很有意思。@[ ]也免除。
DavidC

9

J,14 12字节

-$:^:3@<:^:*

由于@ Leaky Nun节省了2个字节。

通过在n > -1 上对n > 0进行三次递归调用并从n中减去结果来计算结果。当n = 0 时,基本情况有不同的情况。在那里计算n - n等于0。

a(n) = n - n = 0           if n = 0
       n - a(a(a(n-1)))    if n > 0

在这里尝试。

说明

-$:^:3@<:^:*  Input: n
           *  Get the sign of n (n = 0 => 0, n > 0 => 1)
         ^:   Execute that many times
                (0 times means it will just be an identity function)
       <:       Decrement n
 $:             Call itself recursively
   ^:3          three times
      @         on n-1
-             Subtract that result from n and return

我认为不需要括号。
Leaky Nun

6

朱莉娅,16个字节

!n=n>0&&n-!!!~-n

在线尝试!

怎么运行的

我们根据!目的重新定义一元运算符。

如果N = 0,则比较n>0返回也是如此!

否则,&&执行后的代码。~-n等于(n-1)2的补码,对n-1!!!递归调用!三次,然后从n中减去结果值。


介意添加解释吗?我不知道-!!~-._ 是怎么回事。
Downgoat

1
没有什么花哨。!只是函数的名称。
丹尼斯,

5

Python,31个字节

a=lambda n:n and n-a(a(a(n-1)))

递归限制和时间限制使上述函数不可行,但从理论上讲,它应该起作用(并且对于小n起作用)。


4

JavaScript(ES6),52个字节

n=>[0,...Array(n)].reduce((p,_,i,a)=>a[i]=i-a[a[p]])

我可能一直很无聊并编写了递归版本,但是该版本要快得多(可以轻松应对最后一个测试用例),而且还可以使用,reduce所以这是一个加号!




3

R,42 41字节

a=function(n)ifelse(n<1,0,n-a(a(a(n-1))))

用法:

> a(1)
1
> a(10)
7

对于较大的值,此递归方法无法很好地扩展n


如果将条件更改为,则应该可以丢失一个字节(以及许多错误的输入错误)n<1。作为其序列,无论如何,它实际上仅是为非负整数定义的。
user5957401

a=function(n)"if"(n,n-a(a(a(n-1))),0)将关闭几个字节。
朱塞佩

3

绿洲,6字节

码:

nbaa-0

扩展版本:

a(n) = nbaa-
a(0) = 0

码:

n      # Push n
 b     # Calculate a(n - 1)
  a    # Calculate a(a(n - 1))
   a   # Calculate a(a(a(n - 1)))
    -  # Subtract a(a(a(n - 1))) from n

在线尝试!


2

Sesos58 55字节

0000000: 16e0d7 bdcdf8 8cdf1b e6cfbb 840d3f bf659b 38e187  ..............?.e.8..
0000015: f8639b 39dc37 fc893f 666c05 7e7ed9 b88b3f ae0d3f  .c.9.7..?fl.~~...?..?
000002a: 676ed8 bd9940 7fdc3b 36619e f1                    gn...@..;6a..

合理地处理多达400个输入,但此后运行时间将大大增加。

在线尝试!选中调试以查看生成的SBIN代码。

Sesos组装

上面的二进制文件是通过组合以下SASM代码生成的。

set numin, set numout

get
jmp
    jmp
        rwd 3, add 1, rwd 1, add 1, fwd 4, sub 1
    jnz
    rwd 3, sub 1
jnz
rwd 3, add 1, fwd 2
jmp
    rwd 1, sub 1, fwd 3, sub 1, fwd 2, add 3
    jmp
        rwd 2
        jmp
            rwd 3
        jnz
        fwd 6, get, rwd 4, sub 1
        jmp
            fwd 1, sub 1
            jmp
                rwd 3
            jnz
            sub 1
            jmp
                fwd 3
            jnz
            rwd 4, sub 1
        jnz
        fwd 1
        jmp
            rwd 1, add 1, fwd 1, add 1
        jnz
        sub 1, fwd 3, sub 1
        jmp
            fwd 3
        jnz
        rwd 1, sub 1
    jnz
    rwd 2, get
    nop
        rwd 3
    jnz
    fwd 3, get, rwd 2
    jmp
        fwd 2, add 1
        jmp
            fwd 3
        jnz
        rwd 1, add 1, rwd 2
        jmp
            rwd 3
        jnz
        fwd 1, sub 1
    jnz
    fwd 2
    jmp
        rwd 2, add 1, fwd 2, sub 1
    jnz
    nop
        get, fwd 3
    jnz
    rwd 1, add 1, fwd 2
jnz
rwd 2, sub 1
jmp
    rwd 1, sub 1, fwd 1, sub 1
jnz
rwd 1, put

2

LISP,61字节

(defun H(N)(if(= N 0)(return-from H 0)(- N(H(H(H(- N 1)))))))

可能不是最佳解决方案,但它可以工作。


1

Java 7,42个字节

int c(int n){return n>0?n-c(c(c(n-1))):0;}

非高尔夫球和测试用例:

在这里尝试。

class Main{
  static int c(int n){
    return n > 0
              ? n - c(c(c(n-1)))
              : 0;
  }

  public static void main(String[] a){
    for(int i = 0; i < 21; i++){
      System.out.println(i + ": " + c(i));
    }
    System.out.println("1000: " + c(1000));
  }
}

输出:

0: 0
1: 1
2: 1
3: 2
4: 3
5: 4
6: 4
7: 5
8: 5
9: 6
10: 7
11: 7
12: 8
13: 9
14: 10
15: 10
16: 11
17: 12
18: 13
19: 13
20: 14
 (last case takes too long..)

1

Ruby,27个字节

明显的实现。

a=->n{n<1?0:n-a[a[a[n-1]]]}

这是一个更长,更快的答案,它会缓存序列中的先前条目。这两个答案仅适用于1.9之后的版本,因为那是->stamb lambda引入Ruby的时候。

->n{r=[0];i=0;(i+=1;r<<i-r[r[r[i-1]]])while i<n;r[n]}


1

Golfscript,26个 25字节

〜[0] {....,(=== \。,@-+} @ *)\;
〜[0] {...)\; == \。,@-+} @ *)\;

在线尝试!

在本地10000花费不到半秒钟。


1

C, 35 32字节

感谢@PeterTaylor,节省了3个字节!

a(n){return n?n-a(a(a(n-1))):0;}

在Ideone上尝试!


2
在C语言中,您可以直接使用整数作为条件,从而节省三字节:a(n){return n?n-a(a(a(n-1))):0;}
Peter Taylor

1
@betseg- :您的代码中也有错误。您应该在之后取出一个?
owacoder '16

1

Javascript ES6,22个字节

a=n=>n&&n-a(a(a(n-1)))

我会很无聊,做递归版本:P


1

VBA,69字节

Function H(N):ReDim G(N):For j=1To N:G(j)=j-G(G(G(j-1))):Next:H=G(N)

眨眼间就可以在测试集上工作,将速度减慢到n = 1000000以上,撞到内存墙中,稍微超过n = 2500万。


1

Pyth,10个字节

L-WbbyFtb3

定义一个函数y。在线试用:演示

这使用了Pyth的相对新功能。您可以使用折叠语法多次应用一个函数。它实际上并没有保存任何字节,我只是出于演示目的使用它。

说明:

L-WbbyFtb3
L            define function y(b), that returns:
    b           b
 -Wb            and subtract the following if b>0
     yF  3      y applied three times to
       tb       b - 1

1

枫树,28 26字节

`if`(n=0,0,n-a(a(a(n-1))))

用法:

> a:=n->ifelse(n=0,0,n-a(a(a(n-1))));
> seq(a(i),i=0..10);
0, 1, 1, 2, 3, 4, 4, 5, 5, 6, 7

1

dc,34个字节

dsn[zdddd1-;a;a;a-r:aln!=L]dsLx;ap

输入是从堆栈的顶部开始的。这必须是堆栈上的唯一项目,因为堆栈深度用作计数器。用法示例:

$ dc
10000dsn[zdddd1-;a;a;a-r:aln!=L]dsLx;ap

这是序列定义的相当简单的实现:

dsn               # Store n as `n', and keep a copy as a depth buffer (see below)
[                 # Open loop definition
 z                # Push stack depth i for i-th term
 dddd             # Duplicate stack depth four times, for a total of five copies
 1-               # Get i-1 for use as index to previous term
                  #   Note that if we hadn't duplicated n above, or left something else
                  #   on the stack, 0-1 would be -1, which is not a valid array index
 ;a;a;a           # Fetch a(a(a(i-1)))
 -                # Calculate i-a(a(a(i-1)))
 r                # Arrange stack to store i-th term: TOS |  i  (i-a(a(a(i-1))))
 :a               # Store i-th term in array `a'
 ln!=L            # Load n. If n!=i, we're not done calculating terms yet, so execute loop
]                 # Close loop definition. Note that we started with five copies of i:
                  #   i-1 was used to get last term
                  #   i-a(...) was used to calculate current term
                  #   ... i :a was used to store current term
                  #   i ln !=L was used to check loop exit condition
                  # One copy of i is left on the stack to increment counter
dsLx              # Duplicate loop macro, store it, and execute copy
;a                # Last i stored on stack from loop will equal n, so use this to get a(n)
p                 # Print a(n)

无论如何,它一开始就很简单……然后发生了高尔夫。



1

C ++(主要是MSVC)

普通版:40字节

int a(int n){return n?n-a(a(a(n-1))):0;}

模板元编程版本:130字节

#define C {constexpr static int a(){return
template<int N>struct H C N-H<H<H<N-1>::a()>::a()>::a();}};template<>struct H<0>C 0;}};

用法:

std::cout << a(20) << '\n';       // Normal version
std::cout << H<20>::a() << '\n';  // Template version

模板版本是最快的代码,因为没有什么比将值最优化地移动到寄存器=>更快的了,H<20>::a()编译为:

mov esi, 14

对于10000,递归版本由于堆栈溢出错误而崩溃,而模板版本由于模板实例化深度而在编译时崩溃。GCC达到900(614)


我认为你不需要之间的空间C,并{在模板元编程版本
扎卡里

@ZacharýMSVC拒绝在没有该空间的情况下进行编译
HatsuPointerKun

啊,我现在看到为什么这似乎保持发生
扎卡里

@Zacharý取决于宏的类型。如果它具有参数,那么我可以删除空间,但是这里没有
-HatsuPointerKun




0

PowerShell v2 +,56个字节

$a={$n=$args[0];if($n){$n-(&$a(&$a(&$a($n-1))))}else{0}}

等效于lambda的PowerShell,以形成递归定义。通过&调用运算符(例如)执行它&$a(5)。需要很长的时间来执行-即使50我的机器上(最近的酷睿i5与8GB RAM)需要大约90秒。

更快的迭代解决方案,59字节

param($n)$o=,0;1..$n|%{$o+=$_-$o[$o[$o[$_-1]]]};$o[-1]*!!$n

之所以更长,是因为我们需要考虑输入0*!!$n最后是)。否则,我们将迭代地构造数组,直到$n每次添加一个新元素,并在末尾输出最后一个元素$o[-1]。超快速- 10000在我的计算机上进行计算大约需要5秒钟。


0

> <>,55 + 2 = 57字节

^~n;
.~-]{:0$
v>1-}32[
v/  /:1-32[
>$:?/$~]{:0$.
/30@2[

该输入应在程序启动时出现在堆栈上,因此该-v标志为+2字节。在线尝试!

这很慢,因为它使用递归来计算结果。使用TIO h(50)需要花费一分钟以上的时间。它返回正确的结果<= 30,所以我有信心它适用于h(10000),我只是没有运行它来查找!

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.