星期一迷你高尔夫1:逆斐波那契解算器


28

星期一迷你高尔夫:每周一发布(希望!)一系列简短的挑战赛。

斐波那契样序列使用相同的方法,获得著名斐波纳契数列 ; 也就是说,每个数字F(n)通过将序列中的前两个数字相加(F(n)= F(n-1)+ F(n-2))或减去后两个数字(F (n)= F(n + 2)-F(n + 1))。主要区别在于这些序列可以以任意两个数字开头。这些序列的零索引是有争议的,但是现在,我们将使用以下规则:

  • 类斐波那契数列中的第0个数字是小于前一个数字的最后一个数字。

例如,斐波那契序列可以写为1, 0, 1, 1, 2, 3, 5...,因此序列中的第0个数字是lone 0

挑战

挑战的目标是编写一个采用三个整数的程序或函数,并且采用任何格式:

  • AB,这是两个用来开始生成序列的数字。
  • N,要输出的结果序列的长度。

并从0开始输出序列的前N个数字。

细节

  • ABN可以采用任何顺序和格式,只要它们在视觉上是分开的即可。如果您使用其他订单/格式,请指定它是什么。
  • 您可以假设ABN始终为正整数。
  • 您可以假定N不大于100,并且所得序列将不包含x >= 2^31
  • 如果A大于B,则B是序列中的第0个数字。
  • 输出必须用空格,逗号和/或换行符分隔。
  • 允许使用尾部空格或换行符,但不能使用尾部逗号。

测试用例

范例1:

8 13 10

8 13开始往后追溯,直到找到一个比前一个更大的数字,我们得到13 8 5 3 2 1 1 0 1。因此,0该序列中的第0个数字。从此开始,我们打印出0了下9个成员:

0 1 1 2 3 5 8 13 21 34

范例2:

23 37 5

再次向后工作以找到第0个数字,我们找到37 23 14 9 5 4 1 3。这次的第0个数字是1,因此我们将其与接下来的4个成员一起打印出来:

1 4 5 9 14

范例3:

4 3 8

有了这个,我们就不必往后找零号了,因为3它小于4

3 7 10 17 27 44 71 115

范例4:

29 47 11

结果:

1 3 4 7 11 18 29 47 76 123 199

计分

这是,因此以字节为单位的最短有效代码获胜。Tiebreaker转到先前发布的提交。下个星期一,9月28日将选择获胜者。祝您好运!

编辑:恭喜您的获胜者@Jakube,使用Pyth获得了惊人的23个字节!


10
我已经删除了您创建的[monday-mini-golf]标签。我认为我们不应为或多或少的任意挑战组创建标签。标记并没有真正告诉您有关挑战的任何信息,如果您想查找所有这些标记,则只需在搜索栏中搜索短语即可。另外,如果您在以后的每期中都包含指向第一个挑战的链接,则这些链接都将在侧栏中的“链接的问题”下链接。
马丁·恩德

@MartinBüttner好,谢谢;我会记住这一点。
ETHproductions 2015年

我可以按需要获取输入(python列表文字[8, 13, 10])吗?
蓝色

3
目前的挑战是编写程序。这是否意味着不允许使用功能?(CC @LuisMendo)
丹尼斯

3
@Dennis对不起,我忘了。也允许使用功能。感谢您指出了这一点!
ETHproductions 2015年

Answers:


12

Pyth,23个字节

AQWgHGA,-HGG)VvwHA,H+GH

在线尝试:演示测试套件

Pyth编程非常不寻常的样式。有时函数式编程有其缺点。

说明:

AQWgHGA,-HGG)VvwHA,H+GH  Q = input list of the two starting numbers
AQ                       G, H = Q (unpacking Q)
  WgHG                   while H >= G:
      A,-HGG                G, H = [H - G, G]
            )            end while
              vw         read a number from input
             V           for N in range(^):
                H           print H
                 A,H+GH     G, H = [H, G + H]

12

视网膜65 54字节

+`(1*),\1(1*)
$2,$1
+`(1*)(,1*);1\B
$1$2$2$1;
^1*,|;1
<empty>

在这里,<empty>代表一条空的尾线。使用以下命令将代码作为单个文件运行-s标志。

输入格式为

A,B;N

数字以一元表示。输出是逗号分隔的列表,也是一元的。例如:

8 13 10

将会

11111111,1111111111111;1111111111

和产量

,1,1,11,111,11111,11111111,1111111111111,111111111111111111111,1111111111111111111111111111111111

说明

+`(1*),\1(1*)
$2,$1

首先,我们将A和减少B到0th和-1st元素。该+告诉视网膜不断重复这个正则表达式替换,直到正则表达式匹配停止或取代不会修改字符串。正则表达式捕获A与组1 (1*),然后可确保B至少一样大的A,同时捕捉B-A\1(1*)成组2,该循环终止一旦这确保A>B

通过将match设置A,BB-A,A,替换就变成了$2,$1

+`(1*)(,1*);1\B
$1$2$2$1;

现在,我们已经在字符串中获得了所需输出的第一个数字(以及之前的一个,以后需要删除它)。现在,此替换将另一个数字添加为最后两个数字的总和,同时采用1from N。因为我们已经有一个数字,所以我们只希望发生这种情况N-1。为此,我们确保\B至少;11在字符串的末尾仍然存在。如果我们将序列的最后两个值称为CD,则正则表达式将捕获C到组1和,D组2中。我们用来写回$1$2。然后,我们还要编写$2$1翻译为的内容,D+C。请注意,我们不会回写1匹配的单个N,从而使它递减。

^1*,|;1
<empty>

最后,我们需要除去序列中的-1st元素以及剩余;1N,我们只需匹配其中的任何一个并将其替换为空字符串即可。


7

Python 2,93 87 67 61 60字节

i,j,l=input()
while j/i:i,j=j-i,i
exec"i,j=j,i+j;print i;"*l

获取输入(作为文字python列表[8,10,13]

算出第0项

然后打印出添加顺序,直到达到长度为止


1
不错的方法。对于无索引循环for _ in[1]*l:,这样做的时间要短一些exec"stuff;"*l
xnor 2015年

@xnor:对我来说似乎更长了。
递归

比较for _ in[1]*l:stuffexec"stuff;"*l。@xnor没有在for循环中放入东西部分。或for _ in[1]*l:exec";"*l

2
您可以替换j>=ij/i。刚刚发现了!(因为您可能假设A,B和N始终是正整数
mbomb007

6

CJam,26 23字节

感谢Dennis节省了3个字节。

q~{_@\-_g)}g\@{_@+_p}*t

按顺序接受输入N B A(以任何空白分隔)。将结果打印为以换行符分隔的列表,并以error终止

在这里测试。

说明

当找到第0个元素时,这又走了一步。即,一旦其中一个值为负数,它将终止。

q~      e# Read and evaluate input, pushing N, B and A on the stack.
{       e# do while...
  _@\-  e#   B, A = A, B-A
  _W>   e#   Check if A is still non-negative.
}g
\@      e# Reorder N B A into A B N.
{       e# Run the following N times...
  _@+   e#   A, B = B, A+B
  _p    e#   Print B.
}*
t       e# The last A, B are still on the stack. We remove them by trying to
        e# execute a ternary operator: it pops the first two values but then
        e# terminates the program with an error, because there is no third value.

q~{_@\-_g)}g\@{_@+_p}*tN B A)保存三个字节。
丹尼斯2015年

当我自己尝试在CJam中解决此问题时,我遇到了示例1的输入问题。现在,我看到此解决方案也无法提供预期的输出。缺陷在哪里?我认为不必进行检查,B>A而是必须进行检查B not smaller than A,但是我无法弄清楚如何在CJam中进行检查。编辑:丹尼斯的解决方案打印正确的输出。
Cabbie407

好吧,我在解决方案中解决了它。
Cabbie407

@ Cabbie407您是正确的,我应该使用<!代替>
Martin Ender 2015年

啊好吧。我不知道该放在哪里!。我只是添加了一个使其工作;)
Cabbie407

5

迷宫58 54 49 46 44字节

感谢Sp3000建议使用按位取反,它节省了两个字节。

??#"{=
  ;  -
@"~~:}
~""
?
"}}:=
(   +
{{\!:

输入格式为 B A N。输出是用换行符分隔的列表。

说明

(稍有过时。基本思想仍然相同,但是代码的布局现在有所不同。)

这使用了与我的CJam答案相同的想法(因此功劳仍然归于Dennis):回溯序列时,直到得到负值(序列的-1st和-2nd元素),我们才停止。然后,我们开始添加它们,然后打印第一个值。

这使用了几个漂亮的迷宫高尔夫球技巧。让我们看一下各节中的代码:

?"
}

IP从?右转开始(显示为A)。在"(无操作)上,它碰到了死胡同,因此它转过身来,?再次执行(读取B)。最后,}移至B辅助堆栈。死胡同节省了一个字节

?
?
}

现在,循环将查找序列的开头:

)(:{
"  -
" "`?...
=}""

)((递增,递减)是一个空操作,但它是必要的,以确保堆栈的顶部在结阳性(使得IP转动东部)。:复制A{B回主堆栈,进行-计算A-BB-A但是,我们真正想要的是,`否定了价值。

现在是四向交叉路口。对于负面结果,IP向左转?,阅读N并移至程序的下一部分。如果结果为零,则IP继续向南移动,在拐角处转弯,并保持循环。如果结果是肯定的,则IP向右转(向西),在拐角处转弯,再向右转(再次向西),因此它也保持在循环中。我认为这可能成为常见的模式,以区分负值和非负值(或正值和非正值):

                v
                "
               """>negative
non-negative <"""

至少对于这种情况,我还没有找到更紧凑/有用的布局。

无论如何,虽然A为非负数,但循环继续,}移至A辅助堆栈并=交换AB

一旦A为负,?读取,N然后进入第二个循环:

 }:=+:
 }   !
?"({{\

我们知道这N是积极的,因此我们可以依靠IP向左转(北)。循环体现在很简单:

}}:=+:!\{{(

在词:移动既NA到辅助堆栈。复制B,与交换副本A并添加A到的另一个副本B。再次复制以打印的当前值B。打印换行符。移动BN返回主堆栈并递减N

如果N为正,则IP将向右转(北)以继续循环。一旦N达到零,代码就会以一种相当奇特的方式终止:

IP一直向前(向西)移动。在?尝试读取另一个整数,但我们已经达到了EOF,所以它实际上推0来代替。`尝试否定那个,但是那仍然是零。因此IP仍然向西移动,在拐角处转弯,然后继续向下移动到@终止程序的位置。

我想如果我能放置@在更便宜的位置(它目前的成本是3个空白字符)转动三个"`成复合无操作(像)(),但我一直无法使这项工作呢。


5

C,105个 102 100字节

main(a,b,n,t){for(scanf("%d%d%d",&a,&b,&n);t=b-a,t>=0;a=t)b=a;for(;n--;b=t)t=a+b,printf("%d ",a=b);}

感谢@ C0deH4cker打高尔夫球2个字节!

Ideone上在线尝试。


4

MATLAB /倍频程,115个125字节

function x=f(x,n)
while x(2)>=x(1)
x=[abs(x(1)-x(2)) x];end
x=x([2 1]);for k=1:n-1
x=[x(1)+x(2) x];end
x=x(n:-1:1);

该函数应称为f([8 13],10)

范例(Matlab):

>> f([8 13],10)
ans =
     0     1     1     2     3     5     8    13    21    34

在线尝试(八度)


根据规则,您可以修改输入,因此f([a b],n)应该允许。
烧杯

@beaker谢谢!我本来打算做的……但是我读了规则“输入和输出可能用空格,逗号或换行符分隔”,并且感到困惑。我要求澄清
Luis Mendo

是的,我不知道x=f(x,n)函数头中是否包含计数...
烧杯

@AlexA。我在回应Luis关于规则“输入和输出可以用空格,逗号或换行符分隔”的评论,而OP的“ A,B和N可以以任何顺序和格式使用,只要它们是明显分开。” 因为A和B在函数头中不再可见,所以我在质疑是否仅允许2个函数参数。
烧杯

3

Haskell,67 65 56字节

a#b|a>b=b:scanl(+)(a+b)(a#b)|1>0=(b-a)#a
n%a=take n.(a#)

感谢@nimi的建议

这定义了一个三进制中缀函数%,该函数以格式调用(n%a)b,例如:

> (10%8)13
[0,1,1,2,3,5,8,13,21,34]

说明

#在第一行定义的二进制infix函数接收两个整数ab然后返回无限斐波那契式序列,其中ab作为连续元素出现。

a#b                                       -- Define a#b:
   |a>b=                                  -- if a>b, then a#b is
        b:                                -- the sequence that starts with b and
          scanl(+)     (a#b)              -- continues with the sums of prefixes of a#b
                  (a+b)                   -- plus the additional term a+b;
                            |1>0=(b-a)#a  -- otherwise, it's (b-a)#a.

该函数%仅采用的第一个n元素a#b


您可以使用let f=a:scanl(+)(a+b)f in f(-> full #:创建斐波那契序列,a#b|a>b=let f=a:scanl(+)(a+b)f in f|1>0=(b-a)#a并保存两个字节
。– nimi

@nimi谢谢;我同意您的想法,总共节省了9个字节。
Zgarb 2015年

3

> <>,对于-v = 32字节为33 31 + 1

&:{:@(?v:}-$&
-1;!?:&<$+{oan::$&

必须使用-v将输入压入堆栈,因为在> <>中解析十进制数字是不平凡的。

说明:

我将在每个(组)操作之后表示堆栈。它以[F(n),F(n + 1),N]开头

第一行将意甲降至其第0个学期:

& removes N from the stack to put it into a register. [F(n), F(n+1)]
:{:@ move the stack and duplicate items to get [F(n+1), F(n), F(n+1), F(n)]
(?v compares the two top items of the stack and branch to the second line if F(n+1) < F(n) [F(n+1), F(n)]
:} move the stack and duplicate its top to get [F(n), F(n+1), F(n)]
- substracts the two top items and put the result on top of the stack [F(n), F(n+1) - F(n)]
$ switchs the top two values of the stack. [F(n+1) - F(n), F(n)]
& retrieve the value from the register. iteration complete, since [F(n+1) - F(n), F(n), N] can also be read as [F(n-1), F(n), N]

第二行沿顺序显示,直到打印出N项:

< changes the code pointer direction to the left [F(0), F(-1)]
& retrieves the stored value back from the stack [F(0), F(-1), N]
:?!; copies N to compare it to 0, stops if it is [F(0), F(-1), N]
1- decreases it [F(0), F(-1), N-1]
& stores it back [F(0), F(-1)]
$:: makes the stack [F(-1), F(0), F(0), F(0)]
n{ prints the top of the stack then left shifts it [F(0), F(0), F(-1)]
ao displays a line feed (ascii character 0x0a) [F(0), F(0), F(-1)]
+ adds the two top values [F(0), F(-1) + F(0)]
$ switch the two top values. iteration complete since [F(-1) + F(0), F(0)] which can be read as [F(1), F(0)]

通过00.将第一行更改为,您应该能够将字节数减少2 &。从理论上讲,!应该可以,但是我认为> <>填充线的宽度以匹配最长的线的宽度(编辑:这就是为什么我认为您排00.在第一位的原因)。
2015年

是的,我不太确定,我看到这里的人在用!以一种忽略空格的方式。我知道fishlanguage.com上的在线解释器无法正常工作,但python解释器可以。&反正很好,谢谢!
亚伦

如果在线解释器位于最长的行上,则它与!?(在行的末尾)一起使用。您可以尝试使用类似的方法1n!,但会出错,但是如果下面有一行内容比其长的内容(如)lorumipsum,则不会。
2015年

“输出必须用空格,逗号和/或换行符分隔。” 抱歉,您必须使用其他版本。干得好!
ETHproductions 2015年

修复它,我用\ n代替空格来节省2个字节
Aaron

2

爪哇,113 78 76字节

值得称赞的是ETHproduction,它提供了我在此答案中使用的算法。

(a,b,n)->{for(;a<=b;b-=a)a=b-a;for(;n-->0;b+=a,a=b-a)System.out.println(b);}

试试这里

说明:

(a,b,n)->{
    for (;a<=b;b=b-a)a=b-a;  //Compute previous terms while a <= b
    for (;n-->0;b=a+b,a=b-a) //Compute and print next terms while n > 0
    System.out.println(b);   //Print term
}

原始方法,113 93字节

看起来更高尔夫;)

String a(int a,int b,int n){return n<0?a+" "+a(b,a+b,n+1):n>0?a>b?a(b,a+b,-n):a(b-a,a,n):"";}

试试看 在这里一下

说明:

String a(int a, int b, int n){
    return 
    n < 0 ?                           //If n < 0
        a + " " + a(b, a + b, n + 1)  //Return a + next terms and increment n.
    :                                 //Else
        n > 0 ?                       //If n > 0
            a > b ?                   //If a > b
                a(b, a + b, -n)       //Negate n and return terms.
            :                         //If a <= b
                a(b - a, a, n)        //Generate previous term.
        :                             //If n == 0
            ""                        //Return nothing.
    ;
}

3
什么?Java比JS短吗?有一定有什么我做错了....
ETHproductions

@ETHproductions我实际上复制了您的算法(然后使用它):P
TheNumberOne 2015年

对我来说很好,我做了一些改进;)我忘了单独打印每个项目在JS中都是有效的。
ETHproductions 2015年

您可以缩短b=b-ab-=a,并且与相同a=b+a。它将保存2个字节
哈维尔·迪亚兹

+1使简短的语言提交变得如此短。通常,Java提交时间最长!
DankMemes

2

Javascript(ES6),83 73 63字节

这可能已经打到最大。我们拭目以待。

(a,b,n)=>{while(a<=b)b-=a=b-a;for(;n--;console.log(a=b-a))b+=a}

取消高尔夫:

function f(a,b,n) {
  // repeat until we find the 0th item...
  while (a <= b) {  // if a = 5, b = 8:
    a = b - a;      // a = (8 - 5) = 3
    b = b - a;      // b = (8 - 3) = 5
  }
  // repeat n times...
  while (n-- > 0) { // if a = 5, b = 8:
    b += a;         // b = (8 + 5) = 13
    a = b - a;      // a = (13 - 5) = 8
    console.log(a); // print out each item
  }
}

1

Mathematica 112

最终会打高尔夫球吗

z[a_, b_, n_] := (
  f[0] := Min[a, b];
  f[1] := Max[a, b];
  f[x_] := f[x - 1] + f[x - 2];
  f /@ Range[n]
  )

1

CJam,40个字节

l~:A;{_@_@)<}{_@\-\}w\{A(:A0>}{_p_@+}w\;

宝贝的步骤。这是我有史以来第一个CJam程序,因此我感到很自豪。

它以与示例相同的形式接受输入。

我现在看到我可以使用{ ... }*构造将其减少到33个字节。

l~:A;{_@_@)<}{_@-z\}w\A{_p_@+}*;;

通过使用三元运算符清理堆栈并产生错误,我什至可以再减少一个。


1

Ruby,141个字节

def u a,b,n,z=""
n<1 ? z.chop : u(b,a+b,n-1,z+"#{a} ")
end 
def d a,b,z=0
a.abs>b ? z : d(b-a,a,[a,b]) 
end 
def f a,b,n
x,y=d a,b 
u x,y,n
end 

执行

f函数产生所需的输出,参数名称与问题中的变量名称匹配

f(8,13,10) # returns => "0 1 1 2 3 5 8 13 21 34"

没什么聪明的:

  • u(up)函数使用递归从a,b开始计算斐波纳契序列中的n个元素
  • d()函数使用递归在给定两个结束元素的情况找到第0个和第一个元素
  • f(fibonacci)函数将两者放在一起

1

Mathematica,59个字节

If[#>#2,LinearRecurrence[{1,1},#2+{0,#},#3],#0[#2-#,#,#3]]&

0

红宝石,81 75 73

a,b,n=23,37,5;while(c=b-a)<a;b,a=a,c;end;p a;[*2..n].map{b=c+a;c,a=a,b;p b}

用range.map替换for-loop时缩短了6个字节

a,b,n=23,37,5;while(c=b-a)<a;b,a=a,c;end;p a;[*2..n].map{p b=c+a;c,a=a,b}

通过移动打印语句另外节省了2个字节




0

Common Lisp,91个字节

(lambda(a b n)(do((x a(- y x))(y b x))((> x y)(dotimes(k n)(print y)(psetf y(+ y x)x y)))))

在线尝试!

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.