根据Stern-Brocot序列输出第n个有理数


30

所述的Stern-Brocot序列是一个Fibonnaci样序列,其可被构造为如下:

  1. 用初始化序列 s(1) = s(2) = 1
  2. 设置柜台 n = 1
  3. 追加s(n) + s(n+1)到序列
  4. 追加s(n+1)到序列
  5. 递增n,返回到步骤3

这等效于:

s(n)= \ begin {cases} 1&\ textrm {if} n = 1 \ s(\ frac n 2)&\ textrm {if} n \ textrm {is偶数} \ s(\ frac {n-1 } 2)+ s(\ frac {n + 1} 2)和\ textrm {otherwise} \ end {cases}

除其他特性外,斯特恩-布罗克序列可用于生成每个可能的正有理数。每个有理数将只生成一次,并且始终以最简单的形式出现。例如,1/3是序列中的第4个有理数,但当量数2/63/9等等都不会出现。

如上所述,我们可以将第n个有理数定义为r(n) = s(n) / s(n+1),其中s(n)第n个Stern-Brocot数是。

您面临的挑战是编写一个程序或函数,该程序或函数将输出使用Stern-Brocot序列生成的第n个有理数。

  • 上面描述的算法是1索引的;如果您输入的内容是0索引,请在答案中说明
  • 所描述的算法仅用于说明目的,可以按照您喜欢的任何方式(硬编码除外)导出输出
  • 可以通过STDIN,功能参数或任何其他合理的输入机制进行输入
  • 输出可以是STDOUT,控制台,函数返回值或任何其他合理的输出流
  • 输出必须是形式为的字符串a/b,其中ab是Stern-Brocot序列中的相关条目。不允许在输出之前评估分数。例如,对于input 12,输出应该为2/5,而不是0.4
  • 不允许出现标准漏洞

这是,因此最短答案(以字节为单位)将获胜。

测试用例

这里的测试用例是1索引的。

n    r(n)
--  ------
1    1/1
2    1/2
3    2/1
4    1/3
5    3/2
6    2/3
7    3/1
8    1/4
9    4/3
10   3/5
11   5/2
12   2/5
13   5/3
14   3/4
15   4/1
16   1/5
17   5/4
18   4/7
19   7/3
20   3/8
50   7/12
100  7/19
1000 11/39

OEIS条目:A002487
出色的数字爱好者视频,讨论顺序:无限小数


输出可以使用Trues代替1s吗?
罗夫霍

1
@Loovjo不,True/2不是有效分数(就我而言)。顺便说一句,True并非总是如此1-有些语言-1在应用按位运算符时会使用它来避免潜在的错误。[需要引用]
Sok



1
@Sok但在Python True中等效于1并且True/2将是1/2
Leaky Nun

Answers:


3

果冻,14字节

3ẋḶŒpḄċ
’Ç”/⁸Ç

在线尝试!

哦,看来我可以用相同的语言击败@Dennis接受的答案。这可以使用OEIS中的公式进行工作:以超二进制(即以0、1、2为数字的二进制)表示方式的数量(数量减去1)。与大多数Jelly程序(作为完整程序或功能工作)不同,该程序仅作为完整程序工作(因为它将部分输出发送到stdout,并返回其余输出;当用作完整程序时,返回值是隐式发送到stdout的,因此所有输出都放在同一位置,但这不适用于函数提交)。

此版本的程序是非常低效的。您可以通过在第一行的n后面放置n来创建一个更快的程序,该程序适用于所有2ⁿ的输入。该程序的性能为O(n ×3ⁿ),因此在这里使n较小非常重要。编写的程序将n设置等于输入,这显然足够大,但在几乎所有情况下也显然太大(但是,它节省了字节)。

说明

和我在Jelly的解释中一样,花括号(例如{the input})中的文本显示的是由于原始程序中缺少操作数而由Jelly自动填充的内容。

辅助函数(计算第n个分母,即第n +1个分子):

3ẋḶŒpḄċ
3ẋ       3, repeated a number of times equal to {the argument}
  Ḷ      Map 3 to [0, 1, 2]
   Œp    Take the cartesian product of that list
     Ḅ   Convert binary (or in this case hyperbinary) to a number
      ċ  Count number of occurrences of {the argument} in the resulting list

前五个字节基本上只是生成直到给定长度的所有可能的超二进制数,例如对于输入3,其输出为[[0,1,2],[0,1,2],[0,1,2 ]],因此笛卡尔积为[[0,0,0],[0,0,1],[0,0,2],[0,1,0],…,[2,2,1], [2,2,2]。基本上只将最后一个条目乘以1,将倒数第二个条目乘以2,将倒数第二个条目乘以4,依此类推,然后相加;尽管这通常用于将二进制转换为十进制,但它可以很好地处理数字2,因此也适用于超二进制。然后,我们计算输入出现在结果列表中的次数,以便在序列中获得适当的条目。(幸运的是,分子和分母遵循相同的顺序)。

主程序(分子和分母的要求,并格式化输出):

’Ç”/⁸Ç
’Ç      Helper function (Ç), run on {the input} minus 1 (‘)
  ”/    {Output that to stdout}; start again with the constant '/'
    ⁸Ç  {Output that to stdout}; then run the helper function (Ç) on the input (⁸)

不知何故,我一直在编写程序来处理I / O所需的字节数几乎等于解决实际问题所需的字节数…


太可惜了,您不是在开玩笑,因为它效率低下-在TIO 12上需要20秒才能完成,而在13天内完全失效!接受,即使我无法验证所有测试用例。
Sok

11

CJam(20字节)

1_{_@_2$%2*-+}ri*'/\

在线演示。请注意,这是0索引。为了让1指数的,更换初始1_T1

解剖

使用Moshe Newman的特征

分数a(n+1)/a(n+2)可以从先前的分数来生成a(n)/a(n+1) = x通过1/(2*floor(x) + 1 - x)

如果可以的x = s/t

  1 / (2 * floor(s/t) + 1 - s/t)
= t / (2 * t * floor(s/t) + t - s)
= t / (2 * (s - s%t) + t - s)
= t / (s + t - 2 * (s % t))

现在,如果我们假设s并且t是互质的,那么

  gcd(t, s + t - 2 * (s % t))
= gcd(t, s - 2 * (s % t))
= gcd(t, -(s % t))
= 1

如此a(n+2) = a(n) + a(n+1) - 2 * (a(n) % a(n+1))完美。

1_           e# s=1, t=1
{            e# Loop...
  _@_2$%2*-+ e#   s, t = t, s + t - 2 * (s % t)
}
ri*          e# ...n times
'/\          e# Separate s and t with a /

喜欢这里的方法,很棒的答案!
2016年

如果向下滚动到OEIS条目,您会发现Mike Stay已经提交了该公式。
尼尔

11

Haskell,78 77 65 58字节

无耻地窃取优化方法为我们提供了:

(s#t)0=show s++'/':show t
(s#t)n=t#(s+t-2*mod s t)$n-1
1#1

感谢@nimi使用infix函数打高尔夫球几个字节!

(仍然)使用基于0的索引。


旧方法:

s=(!!)(1:1:f 0)
f n=s n+s(n+1):s(n+1):(f$n+1)
r n=show(s n)++'/':(show.s$n+1)

该死的输出格式...和索引运算符。编辑:和优先。

有趣的事实:如果异构列表是一回事,那么最后一行可能是:

r n=show>>=[s!!n,'/',s!!(n+1)]

使用警戒绑定s!!n应短一个字节:f n|x<-s!!n=x:x+x+1:f$n+1
Laikoni '16

@Laikoni s!!n+1不是,(s!!n)+1但这s!!(n+1)就是为什么我不能这样做:/
ThreeFx

确实,这应该是显而易见的。它只是...有那么多s!!n
Laikoni

1
您可以使用++'/':(show.s$n+1)in r保存一个字节。
nimi

1
切换到中缀函数:(s#t)0=show...(s#t)n=t#(s+t-2*mod s t)$n-1r=1#1。您甚至可以忽略r,即最后一行是1#1
nimi

6

果冻,16 字节

L‘Hị⁸Sṭ
1Ç¡ṫ-j”/

在线尝试!验证所有测试用例

怎么运行的

1Ç¡ṫ-j”/  Main link. Argument: n

1         Set the return value to 1.
 Ç¡       Apply the helper link n times.
   ṫ-     Tail -1; extract the last two items.
     j”/  Join, separating by a slash.


L‘Hị⁸Sṭ   Helper link. Argument: A (array)

L         Get the length of A.
 ‘        Add 1 to compute the next index.
  H       Halve.
   ị⁸     Retrieve the item(s) of A at those indices.
          If the index in non-integer, ị floors and ceils the index, then retrieves
          the items at both indices.
    S     Compute the sum of the retrieved item(s).
     ṭ    Tack; append the result to A.

5

05AB1E34 33 25 23字节

XX‚¹GÂ2£DO¸s¦ìì¨}R2£'/ý

说明

XX‚                        # push [1,1]
   ¹G           }          # input-1 times do
     Â                     # bifurcate
      2£                   # take first 2 elements of reversed list
        DO¸                # duplicate and sum 1st copy, s(n)+s(n+1)
           s¦              # cut away the first element of 2nd copy, s(n)
             ìì            # prepend both to list
               ¨           # remove last item in list
                 R2£       # reverse and take the first 2 elements
                    '/ý    # format output
                           # implicitly print

在线尝试

感谢Adnan,节省了2个字节。


这是否也工作?: XX‚¹GÂ2£DO¸s¦ìì¨}R2£'/ý
阿德南

@Adnan确实。我忘了ý可以格式化列表。真好
Emigna '16

4

MATL,20字节

FT+"@:qtPXnosV47]xhh

它使用OEIS页中给出的二项式系数来表征。

该算法理论上适用于所有数字,但实际上受MATL数值精度的限制,因此不适用于大型条目。20至少对于输入,结果是准确的。

在线尝试!

说明

FT+      % Implicitly take input n. Add [0 1] element-wise. Gives [n n+1]
"        % For each k in [n n+1]
  @:q    %   Push range [0 1 ... k-1]
  tP     %   Duplicate and flip: push [k-1 ... 1 0]
  Xn     %   Binomial coefficient, element-wise. Gives an array
  os     %   Number of odd entries in that array
  V      %   Convert from number to string
  47     %   Push 47, which is ASCII for '\'
]        % End for each
x        % Remove second 47
hh       % Concatenate horizontally twice. Automatically transforms 47 into '\'
         % Implicitly display

4

Python 2,85 81字节

x,s=input(),[1,1]
for i in range(x):s+=s[i]+s[i+1],s[i+1]
print`s[x-1]`+"/"+`s[x]`

此提交为1索引。

使用递归函数,为85个字节:

s=lambda x:int(x<1)or x%2 and s(x/2)or s(-~x/2)+s(~-x/2)
lambda x:`s(x)`+"/"+`s(x+1)`

如果类似的输出True/2是可接受的,则为81个字节:

s=lambda x:x<1 or x%2 and s(x/2)or s(-~x/2)+s(~-x/2)
lambda x:`s(x)`+"/"+`s(x+1)`

3

JavaScript(ES6),43个字节

f=(i,n=0,d=1)=>i?f(i-1,d,n+d-n%d*2):n+'/'+d

1分索引;更改n=1为0索引。相对于前两个术语,链接的OEIS页面对于每个术语具有有用的递归关系。我只是将其重新解释为相对于上一个分数的每个分数的重复发生。不幸的是,我们没有嵌入式TeX,因此您只需将其粘贴到另一个站点上,以了解这种格式:

abba+b2(amodb)

3

Python 2,66字节

f=lambda n:1/n or f(n/2)+n%2*f(-~n/2)
lambda n:`f(n)`+'/'+`f(n+1)`

使用递归公式。


3

C(GCC),79个字节

使用基于0的索引。

s(n){return!n?:n%2?s(n/2):s(-~n/2)+s(~-n/2);}r(n){printf("%d/%d",s(n),s(n+1));}

伊迪奥


1
x?:y是gcc扩展名。
rici

3

其实是18个位元组

11,`│;a%τ@-+`nk'/j

在线尝试!

该解决方案使用彼得公式,并且同样采用0索引。感谢Leaky Nun提供了一个字节。

说明:

11,`│;a%τ@-+`nk'/j
11                  push 1, 1
  ,`│;a%τ@-+`n      do the following n times (where n is the input):
                      stack: [t s]
    │                 duplicate the entire stack ([t s t s])
     ;                dupe t ([t t s t s])
      a               invert the stack ([s t s t t])
       %              s % t ([s%t s t t])
        τ             multiply by 2 ([2*(s%t) s t t])
         @-           subtract from s ([s-2*(s%t) s t])
           +          add to t ([t+s-2*(s%t) t])
                      in effect, this is s,t = t,s+t-2*(s%t)
              k'/j  push as a list, join with "/"


@LeakyNun我将推迟进行改进,直到OP做出澄清为止。
Mego


2

R,93个字节

f=function(n)ifelse(n<3,1,ifelse(n%%2,f(n/2-1/2)+f(n/2+1/2),f(n/2)))
g=function(n)f(n)/f(n+1)

从字面上看是最简单的实现。打一点高尔夫球。


2

m4,131个字节

define(s,`ifelse($1,1,1,eval($1%2),0,`s(eval($1/2))',`eval(s(eval(($1-1)/2))+s(eval(($1+1)/2)))')')define(r,`s($1)/s(eval($1+1))')

定义一个宏r,以便r(n)根据规范进行评估。根本不打高尔夫球,我只是对公式进行了编码。


2

Ruby,49个字节

这是0索引,并使用Peter Taylor的公式。欢迎打高尔夫球。

->n{s=t=1;n.times{s,t=t,s+t-2*(s%t)};"#{s}/#{t}"}

1

> <>,34 + 2 = 36字节

在看到Peter Taylor的出色答案后,我重新编写了测试答案(使用非常笨拙的递归,这是一个令人尴尬的82字节)。

&01\$n"/"on;
&?!\:@}:{:@+@%2*-&1-:

它期望输入存在于堆栈中,因此该-v标志为+2个字节。在线尝试!


1

八度,90字节

function f(i)S=[1 1];for(j=1:i/2)S=[S S(j)+S(j+1) (j+1)];end;printf("%d/%d",S(i),S(i+1));end

1

C#,91个 90字节

n=>{Func<int,int>s=_=>_;s=m=>1==m?m:s(m/2)+(0==m%2?0:s(m/2+1));return$"{s(n)}/{s(n+1)}";};

转换为Func<int, string>。这是递归的实现。

取消高尔夫:

n => 
{
    Func<int,int> s = _ => _; // s needs to be set to use recursively. _=>_ is the same byte count as null and looks cooler.
    s = m =>
        1 == m ? m               // s(1) = 1
        : s(m/2) + (0 == m%2 ? 0 // s(m) = s(m/2) for even
        : s(m/2+1));             // s(m) = s(m/2) + s(m/2+1) for odd
    return $"{s(n)}/{s(n+1)}";
};

编辑:-1字节。事实证明,C#在插入的字符串之间return和之间不需要空格$



1

J,29个字节

([,'/',])&":&([:+/2|]!&i.-)>:

用法

n的大值需要后缀,x该后缀表示使用扩展整数。

   f =: ([,'/',])&":&([:+/2|]!&i.-)>:
   f 1
1/1
   f 10
3/5
   f 50
7/12
   f 100x
7/19
   f 1000x
11/39

100算作“大价值”?
dcsohl

1
@dcsohl在此方法中,将计算二项式系数,对于n = 100,计算出的最大二项式系数为C(72,28)= 75553695443676829680> 2 ^ 64,并且需要扩展整数以避免浮点值。
2016年

1

数学,108个 106 101字节

(s={1,1};n=1;a=AppendTo;t=ToString;Do[a[s,s[[n]]+s[[++n]]];a[s,s[[n]]],#];t@s[[n-1]]<>"/"<>t@s[[n]])&

1

R,84字节

function(n,K=c(1,1)){for(i in 1:n)K=c(K,K[i]+K[i+1],K[i+1])
paste0(K[i],"/",K[i+1])}

在线尝试!

旧的[R执行不遵循规范,返回一个浮点数,而不是字符串,所以这里是一个没有。

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.