Xuất số hữu tỷ thứ n theo trình tự Stern-Brocot


30

Trình tự Stern-Brocot là một chuỗi giống như Fibonnaci có thể được xây dựng như sau:

  1. Khởi tạo chuỗi với s(1) = s(2) = 1
  2. Đặt bộ đếm n = 1
  3. Nối s(n) + s(n+1)vào chuỗi
  4. Nối s(n+1)vào chuỗi
  5. Tăng n, trở lại bước 3

Điều này tương đương với:

s (n) = \ started {case} 1 & \ textrm {if} n = 1 \ s (\ frac n 2) & \ textrm {if} n \ textrm {is thậm chí} \ s (\ frac {n-1 } 2) + s (\ frac {n + 1} 2) & \ textrm {nếu không} \ end {case}

Trong số các thuộc tính khác, chuỗi Stern-Brocot có thể được sử dụng để tạo ra mọi số hữu tỷ dương có thể. Mỗi số hữu tỷ sẽ được tạo chính xác một lần và nó sẽ luôn xuất hiện theo các thuật ngữ đơn giản nhất; ví dụ, 1/3là số hữu tỷ thứ 4 trong chuỗi, nhưng các số tương đương 2/6, 3/9v.v ... hoàn toàn không xuất hiện.

Chúng ta có thể định nghĩa số hữu tỷ thứ n là r(n) = s(n) / s(n+1), s(n)số Stern-Brocot thứ n, như được mô tả ở trên.

Thử thách của bạn là viết một chương trình hoặc hàm sẽ xuất ra số hữu tỷ thứ n được tạo bằng chuỗi Stern-Brocot.

  • Các thuật toán được mô tả ở trên là 1 chỉ mục; nếu mục nhập của bạn là 0 chỉ mục, xin vui lòng nêu trong câu trả lời của bạn
  • Các thuật toán được mô tả chỉ nhằm mục đích minh họa, đầu ra có thể được lấy theo bất kỳ cách nào bạn muốn (ngoài mã hóa cứng)
  • Đầu vào có thể thông qua STDIN, tham số chức năng hoặc bất kỳ cơ chế đầu vào hợp lý nào khác
  • Ouptut có thể là STDOUT, bàn điều khiển, giá trị trả về của hàm hoặc bất kỳ luồng đầu ra hợp lý nào khác
  • Đầu ra phải là một chuỗi trong biểu mẫu a/b, trong đó ablà các mục có liên quan trong chuỗi Stern-Brocot. Đánh giá phân số trước khi đầu ra không được phép. Ví dụ, đối với đầu vào 12, đầu ra nên 2/5, không 0.4.
  • Các sơ hở tiêu chuẩn không được phép

Đây là , vì vậy câu trả lời ngắn nhất tính bằng byte sẽ thắng.

Các trường hợp thử nghiệm

Các trường hợp thử nghiệm ở đây là 1 chỉ mục.

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

Mục nhập OEIS: A002487 Video Numberphile
xuất sắc thảo luận về trình tự: Phân số vô hạn


Đầu ra có thể sử dụng Trues thay vì 1s?
Loovjo

1
@Loovjo Không, True/2không phải là một phân số hợp lệ (theo như tôi quan tâm). Bên cạnh đó, Truekhông phải lúc nào cũng vậy 1- một số ngôn ngữ sử dụng -1thay thế để tránh những lỗi tiềm ẩn khi áp dụng các toán tử bitwise. [cần dẫn nguồn]
Sok



1
@Sok nhưng trong Python, Truetương đương 1True/2sẽ có 1/2.
Leaky Nun

Câu trả lời:


3

Thạch , 14 byte

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

Hãy thử trực tuyến!

Ồ, có vẻ như tôi có thể đánh bại câu trả lời được chấp nhận bởi @Dennis, và trong cùng một ngôn ngữ. Điều này hoạt động bằng cách sử dụng một công thức từ OEIS: số cách để thể hiện (số trừ 1) trong hyperbinary (tức là nhị phân với 0, 1, 2 dưới dạng chữ số). Không giống như hầu hết các chương trình Jelly (hoạt động như một chương trình đầy đủ hoặc một chức năng), chương trình này chỉ hoạt động như một chương trình đầy đủ (vì nó gửi một phần của đầu ra đến thiết bị xuất chuẩn và trả về phần còn lại; khi được sử dụng như một chương trình đầy đủ, giá trị trả về được gửi đến thiết bị xuất chuẩn hoàn toàn, vì vậy tất cả đầu ra đều ở cùng một vị trí, nhưng điều này sẽ không hoạt động để gửi chức năng).

Phiên bản này của chương trình rất không hiệu quả. Bạn có thể tạo một chương trình nhanh hơn nhiều, hoạt động cho tất cả đầu vào lên đến 2ⁿ thông qua việc đặt n ngay sau dòng đầu tiên; chương trình có hiệu suất O ( n × 3ⁿ), vì vậy việc giữ n nhỏ là khá quan trọng ở đây. Chương trình dưới dạng tập hợp n bằng với đầu vào, rõ ràng đủ lớn, nhưng rõ ràng là quá lớn trong hầu hết các trường hợp (nhưng hey, nó tiết kiệm byte).

Giải trình

Như thường lệ trong phần giải thích Jelly của tôi, văn bản trong dấu ngoặc nhọn (ví dụ {the input}) hiển thị nội dung được Jelly tự động điền vào do thiếu toán hạng trong chương trình gốc.

Hàm trợ giúp (tính toán mẫu số thứ n , tức là tử số 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

Năm byte đầu tiên về cơ bản chỉ tạo ra tất cả các số siêu liên kết có thể có độ dài nhất định, ví dụ với đầu vào 3, đầu ra là [[0,1,2], [0,1,2], [0,1,2 ]] vì vậy sản phẩm cartesian là [[0,0,0], [0,0,1], [0,0,2], [0,1,0], khác, [2,2,1], [2,2,2]]. về cơ bản chỉ cần nhân mục nhập cuối cùng với 1, mục nhập áp chót bằng 2, mục nhập chống đối với 4, v.v., sau đó thêm vào; Mặc dù điều này thường được sử dụng để chuyển đổi nhị phân thành số thập phân, nhưng nó có thể xử lý tốt chữ số 2, và do đó cũng hoạt động cho hyperbinary. Sau đó, chúng tôi đếm số lần đầu vào xuất hiện trong danh sách kết quả, để có được một mục thích hợp trong chuỗi. (May mắn thay, tử số và mẫu số theo cùng một chuỗi).

Chương trình chính (yêu cầu tử số và mẫu số và định dạng đầu ra):

’Ç”/⁸Ç
’Ç      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 (⁸)

Bằng cách nào đó tôi tiếp tục viết các chương trình cần gần như nhiều byte để xử lý I / O như chúng làm để giải quyết vấn đề thực tế.


Rất tiếc, bạn không đùa về việc nó không hiệu quả - trên TIO 12 phải mất 20 giây để hoàn thành và hoàn thành 13 lần! Được chấp nhận, mặc dù tôi không thể xác minh tất cả các trường hợp thử nghiệm.
Sok

11

CJam (20 byte)

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

Bản demo trực tuyến . Lưu ý rằng đây là 0 chỉ mục. Để làm cho nó 1 chỉ mục, thay thế ban đầu 1_bằng T1.

Mổ xẻ

Điều này sử dụng đặc tính do Moshe Newman

phần a(n+1)/a(n+2)có thể được tạo ra từ các phần trước a(n)/a(n+1) = xbởi1/(2*floor(x) + 1 - x)

Nếu x = s/tsau đó chúng tôi nhận được

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

Bây giờ, nếu chúng ta giả định điều đó stlà nguyên nhân

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

Vì vậy, a(n+2) = a(n) + a(n+1) - 2 * (a(n) % a(n+1))hoạt động hoàn hảo.

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 /

Yêu phương pháp luận ở đây, câu trả lời tuyệt vời!
Sok

Nếu bạn cuộn tiếp xuống mục OEIS, bạn sẽ thấy Mike Stay đã gửi công thức đó.
Neil

11

Haskell, 78 77 65 58 byte

Ăn cắp một cách đáng xấu hổ phương pháp tối ưu hóa cho chúng ta:

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

Cảm ơn @nimi đã chơi golf một vài byte bằng cách sử dụng hàm infix!

(Vẫn) sử dụng lập chỉ mục dựa trên 0.


Cách tiếp cận cũ:

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)

Chết tiệt định dạng đầu ra ... Và các toán tử lập chỉ mục. EDIT: Và ưu tiên.

Sự thật thú vị: nếu danh sách không đồng nhất là một thứ, dòng cuối cùng có thể là:

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

Sử dụng bộ bảo vệ để liên kết s!!nnên ngắn hơn một byte:f n|x<-s!!n=x:x+x+1:f$n+1
Laikoni

@Laikoni s!!n+1thì không (s!!n)+1nhưng s!!(n+1)đó là lý do tại sao tôi không thể làm điều đó: /
ThreeFx

Thật vậy, điều đó nên được hiển nhiên. Nó chỉ ... rất nhiều s!!ntrong đó!
Laikoni

1
Bạn có thể sử dụng ++'/':(show.s$n+1)trong rlưu một byte.
nimi

1
Chuyển sang một một chức năng ghi vào: (s#t)0=show..., (s#t)n=t#(s+t-2*mod s t)$n-1, r=1#1. Bạn thậm chí có thể bỏ qua r, tức là dòng cuối cùng chỉ 1#1.
nimi

6

Thạch , 16 byte

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

Hãy thử trực tuyến! hoặc xác minh tất cả các trường hợp thử nghiệm .

Làm thế nào nó hoạt động

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 byte

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

Giải trình

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

Dùng thử trực tuyến

Đã lưu 2 byte nhờ Adnan.


Điều này cũng làm việc ?: XX‚¹GÂ2£DO¸s¦ìì¨}R2£'/ý.
Ad Nam

@Ad Nam Thật vậy. Tôi quên rằng ýcó thể định dạng một danh sách. Tốt đẹp.
Emigna

4

MATL , 20 byte

FT+"@:qtPXnosV47]xhh

Điều này sử dụng đặc tính theo các hệ số nhị thức được đưa ra trong trang OEIS .

Thuật toán hoạt động trên lý thuyết cho tất cả các số, nhưng trong thực tế, nó bị giới hạn bởi độ chính xác số của MATL và do đó, nó không hoạt động đối với các mục lớn. Kết quả là chính xác cho đầu vào tối 20thiểu.

Hãy thử trực tuyến!

Giải trình

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 byte

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]`

Trình này là 1 chỉ mục.

Sử dụng hàm đệ quy, 85 byte:

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)`

Nếu một đầu ra như True/2được chấp nhận, thì đây là một ở mức 81 byte:

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 byte

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

1 chỉ số; thay đổi thành n=10-index. Trang OEIS được liên kết có mối quan hệ lặp lại hữu ích cho mỗi thuật ngữ theo hai điều khoản trước đó; Tôi chỉ giải thích lại nó như là một sự tái phát cho từng phân số về phân số trước đó. Thật không may, chúng tôi không có TeX nội tuyến nên bạn sẽ phải dán nó lên một trang web khác để tìm hiểu làm thế nào các định dạng này:

abba+b2(amodb)

3

Python 2, 66 byte

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

Sử dụng công thức đệ quy.


3

C (GCC), 79 byte

Sử dụng lập chỉ mục dựa trên 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));}

Ý tưởng


1
x?:ylà một phần mở rộng gcc.
rici

3

Trên thực tế, 18 byte

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

Hãy thử trực tuyến!

Giải pháp này sử dụng công thức của Peter và được lập chỉ mục 0. Cảm ơn Leaky Nun cho một byte.

Giải trình:

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 Tôi sẽ giữ sự cải thiện đó cho đến khi có sự làm rõ từ OP.
Mego

2

MATL , 32 30 byte

1i:"tt@TF-)sw@)v]tGq)V47bG)Vhh

Điều này sử dụng một cách tiếp cận trực tiếp: tạo ra đủ thành viên của chuỗi, chọn hai cái mong muốn và định dạng đầu ra.

Hãy thử trực tuyến!


2

R, 93 byte

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)

Nghĩa đen là thực hiện đơn giản nhất. Làm việc trên sân golf một chút.


2

m4, 131 byte

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))')

Xác định một macro rsao cho r(n)đánh giá theo thông số kỹ thuật. Không thực sự chơi golf chút nào, tôi chỉ mã hóa công thức.


2

Ruby, 49 byte

Đây là 0 chỉ mục và sử dụng công thức của Peter Taylor. Gợi ý chơi golf chào mừng.

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

1

> <> , 34 + 2 = 36 byte

Sau khi thấy câu trả lời xuất sắc của Peter Taylor, tôi đã viết lại câu trả lời kiểm tra của mình (đó là 82 byte đáng xấu hổ, sử dụng đệ quy rất vụng về).

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

Nó hy vọng đầu vào sẽ có mặt trên ngăn xếp, vì vậy +2 byte cho -vcờ. Hãy thử trực tuyến!


1

Octave, 90 byte

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 byte

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)}";};

Diễn viên đến Func<int, string>. Đây là việc thực hiện đệ quy.

Ung dung:

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)}";
};

Chỉnh sửa: -1 byte. Hóa ra C # không cần khoảng trắng giữa return$cho các chuỗi được nội suy.



1

J, 29 byte

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

Sử dụng

Các giá trị lớn của n yêu cầu một hậu tố xbiểu thị việc sử dụng các số nguyên mở rộng.

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

100được tính là "giá trị lớn"?
dcsohl

1
@dcsohl Trong phương pháp này, các hệ số nhị thức được tính toán và với n = 100, hệ số lớn nhất được tính là C (72, 28) = 75553695443676829680> 2 ^ 64 và sẽ yêu cầu các số nguyên mở rộng để tránh các giá trị dấu phẩy động.
dặm

1

Toán học, 108 106 101 byte

(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 byte

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

Hãy thử trực tuyến!

Việc triển khai R cũ hơn không tuân theo các thông số kỹ thuật, trả về một dấu phẩy động chứ không phải là một chuỗi, vì vậy đây là một điểm thực hiện.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.