ส่งออกจำนวนตรรกยะที่ n ตามลำดับ Stern-Brocot


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) = \ start {คดี} 1 & \ textrm {if} n = 1 \ s (\ frac n 2) & \ textrm {ถ้า} n \ textrm {คือแม้แต่} \ s (\ frac {n-1 } 2) + s (\ frac {n + 1} 2) & \ textrm {เป็นอย่างอื่น} \ end {คดี}

ในบรรดาคุณสมบัติอื่น ๆ ลำดับ Stern-Brocot สามารถใช้เพื่อสร้างจำนวนตรรกยะเชิงบวกที่เป็นไปได้ทั้งหมด จำนวนตรรกยะทุกตัวจะถูกสร้างขึ้นหนึ่งครั้งและจะปรากฏในเงื่อนไขที่ง่ายที่สุดเสมอ ตัวอย่างเช่น1/3เป็นจำนวนตรรกยะที่ 4 ในลำดับ แต่ตัวเลขที่เทียบเท่า2/6และ3/9อื่น ๆ จะไม่ปรากฏเลย

เราสามารถกำหนดจำนวนตรรกยะที่ n เป็นr(n) = s(n) / s(n+1)โดยที่s(n)หมายเลขสเติร์น - โบรคต์ดังที่อธิบายไว้ข้างต้น

ความท้าทายของคุณคือการเขียนโปรแกรมหรือฟังก์ชั่นที่จะส่งออกจำนวนเหตุผลที่ n ที่สร้างขึ้นโดยใช้ลำดับ Stern-Brocot

  • อัลกอริทึมที่อธิบายไว้ข้างต้นได้รับการจัดทำดัชนี 1 ชุด ถ้ารายการของคุณถูกจัดทำดัชนี 0 โปรดระบุคำตอบของคุณ
  • อัลกอริธึมที่อธิบายไว้มีวัตถุประสงค์เพื่อเป็นตัวอย่างเท่านั้นเอาต์พุตสามารถได้มาในแบบที่คุณชอบ (นอกเหนือจากการเข้ารหัสแบบฮาร์ด)
  • อินพุตสามารถผ่าน STDIN พารามิเตอร์ฟังก์ชันหรือกลไกอินพุตที่เหมาะสมอื่น ๆ
  • Ouptut สามารถไปที่ STDOUT คอนโซลค่าส่งคืนฟังก์ชันหรือสตรีมเอาต์พุตอื่น ๆ ที่สมเหตุสมผล
  • ผลลัพธ์จะต้องเป็นสตริงในรูปแบบa/bที่ไหนaและbเป็นรายการที่เกี่ยวข้องในลำดับ Stern-Brocot การประเมินเศษส่วนก่อนส่งออกจะไม่ได้รับอนุญาต ตัวอย่างเช่นสำหรับการป้อนข้อมูล12การส่งออกควรจะเป็นไม่ได้2/50.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 ได้หรือไม่?
Loovjo

1
@Loovjo ไม่True/2ไม่ใช่เศษส่วนที่ถูกต้อง (เท่าที่ฉันกังวล) เช่นกันTrueไม่ได้เสมอ1- บางภาษาใช้-1แทนเพื่อหลีกเลี่ยงความผิดพลาดที่อาจเกิดขึ้นเมื่อมีการใช้ผู้ประกอบการระดับบิต [จำเป็น]
Sok



1
@Sok แต่ในหลาม, Trueเทียบเท่ากับ1และจะเป็นTrue/2 1/2
Leun Nun

คำตอบ:


3

เยลลี่ขนาด 14 ไบต์

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

ลองออนไลน์!

Ooh ดูเหมือนว่าฉันจะเอาชนะคำตอบที่ได้รับการยอมรับจาก @Dennis และในภาษาเดียวกันกับที่ สิ่งนี้ทำงานโดยใช้สูตรจาก OEIS: จำนวนวิธีที่จะแสดง (จำนวนลบ 1) ในระดับไฮเปอร์ไบนารี (เช่นไบนารีที่มี 0, 1, 2 เป็นตัวเลข) แตกต่างจากโปรแกรม Jelly ส่วนใหญ่ (ซึ่งใช้งานได้ทั้งโปรแกรมหรือฟังก์ชั่น) โปรแกรมนี้ใช้งานได้เป็นโปรแกรมเต็มรูปแบบเท่านั้น (เพราะมันส่งส่วนหนึ่งของเอาต์พุตไปยัง stdout และส่งคืนส่วนที่เหลือเมื่อใช้เป็นโปรแกรมแบบเต็ม ถูกส่งไปยัง stdout โดยปริยายดังนั้นเอาต์พุตทั้งหมดจะอยู่ในที่เดียวกัน แต่สิ่งนี้จะไม่ทำงานสำหรับการส่งฟังก์ชั่น)

โปรแกรมรุ่นนี้ไม่มีประสิทธิภาพมาก คุณสามารถสร้างโปรแกรมที่เร็วกว่าซึ่งทำงานได้กับอินพุตทั้งหมดถึง2ⁿผ่านการวางnหลังบรรทัดแรก โปรแกรมมีประสิทธิภาพ O ( n ×3ⁿ) ดังนั้นการรักษาnขนาดเล็กจึงมีความสำคัญพอสมควร โปรแกรมที่เขียนเป็นชุดnเท่ากับอินพุตซึ่งมีขนาดใหญ่พออย่างชัดเจน แต่ก็มีขนาดใหญ่เกินไปอย่างชัดเจนในเกือบทุกกรณี (แต่เฮ้มันช่วยประหยัดไบต์)

คำอธิบาย

ตามปกติในคำอธิบายเยลลี่ของฉันข้อความในเครื่องหมายปีกกา (เช่น{the input}) แสดงสิ่งที่เจลลี่กรอกโดยอัตโนมัติเนื่องจากตัวถูกดำเนินการหายไปในโปรแกรมต้นฉบับ

ฟังก์ชั่นตัวช่วย (คำนวณส่วนที่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

ห้าไบต์แรกนั้นโดยทั่วไปจะสร้างตัวเลข hyperbinary ที่เป็นไปได้ทั้งหมดตามความยาวที่กำหนดเช่นกับอินพุต 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, รายการ antepenultimate 4 และอื่น ๆ จากนั้นเพิ่ม; แม้ว่าโดยปกติจะใช้เพื่อแปลงเลขฐานสองเป็นทศนิยม แต่ก็สามารถจัดการกับตัวเลข 2 ได้ดีและใช้งานกับ hyperbinary เช่นกัน จากนั้นเราจะนับจำนวนครั้งที่อินพุตปรากฏในรายการผลลัพธ์เพื่อรับรายการที่เหมาะสมในลำดับ (โชคดีที่ตัวเศษและตัวส่วนเป็นไปตามลำดับเดียวกัน)

โปรแกรมหลัก (ถามถึงตัวเศษและส่วนและฟอร์แมตเอาต์พุต):

’Ç”/⁸Ç
’Ç      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 ครั้งโดยสมบูรณ์! ยอมรับแม้ว่าฉันจะไม่สามารถตรวจสอบกรณีทดสอบทั้งหมดได้

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มี coprime แล้ว

  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

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

@Laikoni s!!n+1ไม่ใช่(s!!n)+1แต่s!!(n+1)นั่นเป็นเหตุผลว่าทำไมฉันถึงทำไม่ได้: /
ThreeFx

แน่นอนว่าควรเห็นได้ชัด มัน ... มีs!!nอยู่มากมายในนั้น!
Laikoni

1
คุณสามารถใช้++'/':(show.s$n+1)ใน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

ลองออนไลน์

บันทึก 2 ไบต์ต้องขอบคุณ Adnan


สิ่งนี้ใช้งานได้หรือไม่: 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

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 ที่เชื่อมโยงมีความสัมพันธ์ที่เกิดขึ้นซ้ำที่มีประโยชน์สำหรับแต่ละคำในแง่ของคำสองคำก่อนหน้า; ฉันแค่ตีความใหม่ว่ามันเป็นการเกิดซ้ำสำหรับแต่ละเศษส่วนในแง่ของเศษส่วนก่อนหน้า น่าเสียดายที่เราไม่มี inline TeX ดังนั้นคุณเพียงแค่วางมันลงบนเว็บไซต์อื่นเพื่อดูว่ารูปแบบนี้เป็นอย่างไร:

aa+-2(aพอควร)

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

Ideone


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 bytes

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

คาดว่าอินพุตจะแสดงบนสแต็กดังนั้น +2 ไบต์สำหรับ-vแฟล็ก ลองออนไลน์!



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>เพื่อปลดเปลื้อง นี่เป็นการใช้งานแบบเรียกซ้ำ

Ungolfed:

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 และจะต้องใช้จำนวนเต็มแบบขยายเพื่อหลีกเลี่ยงค่าทศนิยม
ไมล์


โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.