Stern-Brocot 시퀀스에 따라 n 번째 유리수를 출력합니다


30

스턴 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 {은 짝수} \ s (\ frac {n-1 } 2) + s (\ frac {n + 1} 2) & \ textrm {otherwise} \ end {cases}

다른 특성 중에서도 Stern-Brocot 시퀀스를 사용하여 가능한 모든 양의 유리수를 생성 할 수 있습니다. 모든 합리적인 숫자는 정확히 한 번 생성되며 항상 가장 간단한 용어로 나타납니다. 예를 들어, 1/3순서의 4 유리수하지만, 해당 숫자이며 2/6, 3/9전혀 표시되지 않습니다는 등.

위에서 설명한 것처럼 n 번째 합리적 숫자를로 정의 할 수 있습니다 r(n) = s(n) / s(n+1). 여기서 s(n)n 번째 Stern-Brocot 수입니다.

문제는 Stern-Brocot 시퀀스를 사용하여 생성 된 n 번째 유리수를 출력하는 프로그램 또는 함수를 작성하는 것입니다.

  • 위에서 설명한 알고리즘은 1- 색인입니다. 출품작의 색인이 0 인 경우 답변에 기재하십시오.
  • 설명 된 알고리즘은 설명 목적으로 만 사용되며 원하는 방식으로 하드 코딩을 제외하고 출력을 도출 할 수 있습니다.
  • STDIN, 기능 매개 변수 또는 기타 합리적인 입력 메커니즘을 통해 입력 할 수 있습니다.
  • Ouptut는 STDOUT, 콘솔, 함수 리턴 값 또는 기타 합리적인 출력 스트림 일 수 있습니다.
  • 출력 형태의 문자열로해야합니다 a/b, a그리고 b스턴 - Brocot 순서에서 관련 항목입니다. 출력 전에 분수를 평가하는 것은 허용되지 않습니다. 예를 들어 input의 12경우 output이 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
시퀀스를 설명하는 탁월한 Numberphile 비디오 : 무한 분수


출력에서 Trues 대신 s를 사용할 수 있습니까 1?
Loovjo

1
@Loovjo 아니요, True/2유효한 분수는 아닙니다 (관심있는 한). 따로, True항상 그런 것은 아닙니다. 1일부 언어는 -1비트 연산자를 적용 할 때 잠재적 실수를 피하기 위해 대신 사용 합니다. [인용 필요]
Sok



1
@Sok하지만 파이썬에서, True에 해당 1하고 True/2있을 것이다 1/2.
Leaky Nun

답변:


3

젤리 , 14 바이트

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

온라인으로 사용해보십시오!

@Dennis가 받아 들일 수있는 대답을 그 언어로 이길 수있는 것처럼 보입니다. 이것은 OEIS의 공식을 사용하여 작동합니다. 하이퍼 바이너리로 표현하는 방법의 수 (숫자 -1) (즉, 숫자가 0, 1, 2 인 이진). 전체 프로그램 또는 함수로 작동하는 대부분의 Jelly 프로그램과 달리이 프로그램은 전체 프로그램으로 만 작동합니다 (출력의 일부를 stdout으로 보내고 나머지를 반환하기 때문에 전체 프로그램으로 사용되는 경우 반환 값) 암시 적으로 stdout으로 전송되므로 모든 출력이 같은 위치에 있지만 함수 제출에는 작동하지 않습니다.

이 프로그램 버전은 매우 비효율적입니다. 첫 번째 줄 바로 다음 에 n 을 배치하여 최대 2 all의 모든 입력에 대해 작동하는 훨씬 빠른 프로그램을 만들 수 있습니다 . 프로그램의 성능 은 O ( n × 3 performance)이므로 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

처음 5 바이트는 기본적으로 주어진 길이까지 가능한 모든 이진수를 생성합니다. 예를 들어 입력 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))

이제, 우리는 그 가정하는 경우 st다음 서로 소입니다

  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 /

여기에서 방법론을 좋아하십시오.
Sok

OEIS 항목을 더 아래로 스크롤하면 Mike Stay가 이미 해당 수식을 제출 한 것을 알 수 있습니다.
Neil

11

하스켈, 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

infix 함수를 사용하여 몇 바이트를 골프에 대한 @nimi에게 감사드립니다!

(여전히) 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것은 1 바이트 더 짧아야합니다.f n|x<-s!!n=x:x+x+1:f$n+1
Laikoni

@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-1)으로 전환하십시오 r=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

05AB1E , 34 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

@Adnan 참으로. ý목록을 포맷 할 수 있다는 것을 잊었습니다 . 좋은.
Emigna

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

파이썬 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

자바 스크립트 (ES6), 43 바이트

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

1- 색인; n=10 인덱싱으로 변경하십시오 . 연결된 OEIS 페이지에는 이전 두 용어와 관련하여 각 용어에 대해 유용한 반복 관계가 있습니다. 나는 단지 이전 분수의 관점에서 각 분수의 반복으로 해석했습니다. 불행히도 우리는 인라인 TeX를 가지고 있지 않으므로 다른 사이트에 붙여 넣기 만하면이 형식을 확인할 수 있습니다.

abba+b2(amodb)

3

파이썬 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?:ygcc 확장입니다.
rici

3

실제로 18 바이트

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

온라인으로 사용해보십시오!

이 솔루션은 Peter의 공식을 사용하며 마찬가지로 인덱스가 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

루비, 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이며 부동 소수점 값을 피하려면 확장 된 정수가 필요합니다.
마일

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]])&

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.