วิธีการเขียนลำดับฟีโบนักชี?


140

ตอนแรกฉันเขียนโปรแกรมผิด แทนที่จะส่งกลับตัวเลข Fibonacci ระหว่างช่วง (เช่น startNumber 1, endNumber 20 ควร = เฉพาะตัวเลขระหว่าง 1 และ 20) ฉันได้เขียนโปรแกรมเพื่อแสดงตัวเลข Fibonacci ทั้งหมดระหว่างช่วง (เช่น startNumber 1, หมายเลขท้าย 20 แสดง = หมายเลข Fibonacci 20 หมายเลขแรก) ฉันคิดว่าฉันมีรหัสที่แน่นอน ฉันยังไม่เห็นว่าทำไมสิ่งนี้จึงเกิดขึ้น

startNumber = int(raw_input("Enter the start number here "))
endNumber = int(raw_input("Enter the end number here "))

def fib(n):
    if n < 2:
        return n
    return fib(n-2) + fib(n-1)

print map(fib, range(startNumber, endNumber))

มีคนชี้ให้เห็นในส่วนที่สองของฉัน (ซึ่งถูกปิดเพราะเป็นสิ่งซ้ำซ้อน - /programming/504193/how-to-write-the-fibonacci-sequence-in-python-part-ii ) จำเป็นต้องผ่าน startNumber และ endNumber ผ่านตัวสร้างโดยใช้ลูป while ใครช่วยกรุณาชี้นำฉันในการทำสิ่งนี้? ยินดีต้อนรับความช่วยเหลือใด ๆ


ฉันเป็นโปรแกรมเมอร์แห่งการเรียนรู้และฉันรู้สึกสับสนเล็กน้อย ฉันถูกขอให้เขียนโปรแกรมที่จะคำนวณและแสดงลำดับของ Fibonacci โดยผู้ใช้ป้อนหมายเลขเริ่มต้นและหมายเลขสิ้นสุด (เช่น startNumber = 20 endNumber = 100 และจะแสดงเฉพาะตัวเลขระหว่างช่วงนั้น) เคล็ดลับคือการใช้มันอย่างรวม (ซึ่งฉันไม่ทราบวิธีการทำใน Python? - ฉันสมมติว่านี่หมายถึงการใช้ช่วงรวม?)

สิ่งที่ฉันมีจนถึงตอนนี้ยังไม่มีการเข้ารหัสที่แท้จริง แต่เป็น:

  • เขียนสูตรลำดับ Fib ให้ไม่มีที่สิ้นสุด
  • แสดง startNumber ไปยัง endNumber เท่านั้นจากลำดับ Fib

ฉันไม่รู้ว่าจะเริ่มจากตรงไหนและฉันขอความคิดหรือข้อมูลเชิงลึกเกี่ยวกับวิธีการเขียนสิ่งนี้ ฉันยังได้พยายามที่จะเขียนฟอรัมลำดับตอแหล แต่ฉันก็หลงทางเช่นกัน

คำตอบ:


257

มีจำนวนมากของข้อมูลเกี่ยวกับลำดับ Fibonacci บนคือวิกิพีเดียและทังสเตน มากกว่าที่คุณต้องการ อย่างไรก็ตามมันเป็นสิ่งที่ดีที่จะเรียนรู้วิธีการใช้ทรัพยากรเหล่านี้เพื่อค้นหา (อย่างรวดเร็วถ้าเป็นไปได้) สิ่งที่คุณต้องการ

เขียนสูตรลำดับ Fib ให้ไม่มีที่สิ้นสุด

ในทางคณิตศาสตร์มันอยู่ในรูปแบบเวียนเกิด:

fibonacci จากวิกิพีเดีย

ในการเขียนโปรแกรมที่ไม่มีที่สิ้นสุดไม่ได้อยู่ คุณสามารถใช้แบบฟอร์มเรียกซ้ำแปลรูปแบบคณิตศาสตร์โดยตรงในภาษาของคุณตัวอย่างเช่นใน Python มันจะกลายเป็น:

def F(n):
    if n == 0: return 0
    elif n == 1: return 1
    else: return F(n-1)+F(n-2)

ลองมันในภาษาของคุณชื่นชอบและเห็นว่ารูปแบบนี้ต้องใช้จำนวนมากของเวลาเป็น n ได้รับใหญ่ อันที่จริงนี่คือ O (2 n ) ในเวลา

ไปในเว็บไซต์ที่ฉันเชื่อมโยงกับคุณและจะเห็นสิ่งนี้ (ในวุลแฟรม ):

สมการ Fibonacci

อันนี้ค่อนข้างง่ายต่อการใช้งานและรวดเร็วมากในการคำนวณใน Python:

from math import sqrt
def F(n):
    return ((1+sqrt(5))**n-(1-sqrt(5))**n)/(2**n*sqrt(5))

อีกวิธีหนึ่งในการทำตามคำจำกัดความ (จากวิกิพีเดีย ):

หมายเลขแรกของลำดับคือ 0 หมายเลขที่สองคือ 1 และแต่ละหมายเลขถัดมาจะเท่ากับผลรวมของตัวเลขสองตัวก่อนหน้าของลำดับนั้นโดยให้ลำดับ 0, 1, 1, 2, 3, 5, 8 ฯลฯ

หากภาษาของคุณรองรับตัววนซ้ำคุณอาจทำสิ่งต่อไปนี้

def F():
    a,b = 0,1
    while True:
        yield a
        a, b = b, a + b

แสดง startNumber ไปยัง endNumber เท่านั้นจากลำดับ Fib

เมื่อคุณรู้วิธีสร้างหมายเลขฟีโบนัชชีคุณเพียงแค่ต้องวนรอบตัวเลขและตรวจสอบว่าพวกเขาตรวจสอบเงื่อนไขที่กำหนด

สมมติว่าตอนนี้คุณเขียน af (n) ที่ส่งคืนคำศัพท์ที่ n ของลำดับฟีโบนักชี (เช่นที่มี sqrt (5))

ในภาษาส่วนใหญ่คุณสามารถทำสิ่งที่ชอบ:

def SubFib(startNumber, endNumber):
    n = 0
    cur = f(n)
    while cur <= endNumber:
        if startNumber <= cur:
            print cur
        n += 1
        cur = f(n)

ในหลามฉันจะใช้แบบฟอร์มตัววนซ้ำและไปเพื่อ:

def SubFib(startNumber, endNumber):
    for cur in F():
        if cur > endNumber: return
        if cur >= startNumber:
            yield cur

for i in SubFib(10, 200):
    print i

คำแนะนำของฉันคือการเรียนรู้ที่จะอ่านสิ่งที่คุณต้องการ Project Euler (google เพื่อมัน) จะฝึกให้คุณทำเช่นนั้น: P ขอให้โชคดีและสนุก!


1
คุณต้องใช้การวนรอบสักครู่ไม่ใช่แมป ลองคิดด้วยตัวคุณเองแล้วกลับมาพร้อมรหัสถ้าคุณทำไม่ได้ ฉันไม่ขี้เกียจ (รหัสสั้นกว่าความคิดเห็นนี้) ฉันทำที่สำหรับคุณลองมันออกมาด้วย "ขณะที่" คำใบ้;) หากคุณมีปัญหากับที่กลับมาอีกครั้ง;)
Andrea Ambu

ฉันกลับมาแล้วฮ่า ๆ ฉันกำจัดฟังก์ชั่น map (range) และฉันใช้เพียงฟังก์ชั่น range (startNumber, endNumber) ตอนนี้ปัญหาที่ฉันมีคือการใช้คำสั่ง while ฉันลองที่จุดเริ่มต้นของฟังก์ชั่น แต่แน่นอนว่ามีรายการข้อผิดพลาดที่ทำเสร็จแล้ว ฉันจะเอาไปวางที่ไหน ขอบคุณ
SD

ลองทำด้วยมือตัวอย่างของอินพุต - เอาต์พุตของโปรแกรมของคุณ (ในช่วงสั้น ๆ ) ลองทำดูว่าโปรแกรมของคุณผิดตรงไหน ลองแปลง "by-hand method" เป็นรหัส นี่คือการออกกำลังกายเพื่อเรียนรู้ ฉันสามารถวางโค้ดสองบรรทัดลงไป แต่ฉันไม่คิดว่าคุณจะเรียนรู้อะไรจากพวกเขา
Andrea Ambu

1
เราควรใช้int(((1+sqrt(5))**n-(1-sqrt(5))**n)/(2**n*sqrt(5)))ความคิดใด ๆ @AndreaAmbu
lord63 j

3
@ lord63.j คุณควรใช้สูตรนั้นก็ต่อเมื่อคุณทราบว่ามันเริ่มเบี่ยงเบนจากค่าจริงเมื่อnสูงกว่า 70 และระเบิดด้วยOverflowError เมื่อnน้อยกว่า 600 เล็กน้อยวิธีอื่น ๆ สามารถจัดการn1,000 หรือมากกว่าโดยไม่ต้องเป่า ขึ้นหรือสูญเสียความแม่นยำ
cdlane

66

เครื่องกำเนิด Pythonic ที่มีประสิทธิภาพของลำดับฟีโบนักชี

ฉันพบคำถามนี้ในขณะที่พยายามรับลำดับ Pythonic ที่สั้นที่สุด (ในภายหลังฉันได้เห็นสิ่งที่คล้ายกันในข้อเสนอ Python Enhancement Proposal ) และฉันไม่ได้สังเกตว่ามีใครบางคนกำลังคิดหาวิธีแก้ปัญหาเฉพาะของฉัน เข้าใกล้ แต่ก็ยังน้อยกว่า) ดังนั้นนี่คือพร้อมความคิดเห็นที่อธิบายการวนซ้ำครั้งแรกเพราะฉันคิดว่าอาจช่วยให้ผู้อ่านเข้าใจ:

def fib():
    a, b = 0, 1
    while True:            # First iteration:
        yield a            # yield 0 to start with and then
        a, b = b, a + b    # a will now be 1, and b will also be 1, (0 + 1)

และการใช้งาน:

for index, fibonacci_number in zip(range(10), fib()):
     print('{i:3}: {f:3}'.format(i=index, f=fibonacci_number))

พิมพ์:

  0:   0
  1:   1
  2:   1
  3:   2
  4:   3
  5:   5
  6:   8
  7:  13
  8:  21
  9:  34
 10:  55

(เพื่อวัตถุประสงค์ในการระบุตัวบุคคลฉันเพิ่งสังเกตเห็นการใช้งานที่คล้ายกันในเอกสาร Python บนโมดูลแม้จะใช้ตัวแปรaและbตอนนี้ฉันจำได้ว่าเคยเห็นมาก่อนเขียนคำตอบนี้ แต่ฉันคิดว่าคำตอบนี้แสดงให้เห็นถึงการใช้ภาษาที่ดีขึ้น)

การใช้งานที่กำหนดไว้ซ้ำ ๆ

สารานุกรมออนไลน์ของจำนวนเต็มลำดับกำหนดลำดับ Fibonacci ซ้ำเป็น

F (n) = F (n-1) + F (n-2) กับ F (0) = 0 และ F (1) = 1

การกำหนดค่านี้ซ้ำ ๆ ใน Python อย่างชัดเจนสามารถทำได้ดังนี้:

def rec_fib(n):
    '''inefficient recursive function as defined, returns Fibonacci number'''
    if n > 1:
        return rec_fib(n-1) + rec_fib(n-2)
    return n

แต่การแทนค่าที่แน่นอนของนิยามทางคณิตศาสตร์นั้นไม่มีประสิทธิภาพอย่างเหลือเชื่อสำหรับตัวเลขที่มากกว่า 30 เพราะแต่ละตัวเลขที่ถูกคำนวณจะต้องคำนวณสำหรับทุกตัวเลขที่อยู่ด้านล่าง คุณสามารถแสดงให้เห็นว่าช้าแค่ไหนโดยใช้สิ่งต่อไปนี้:

for i in range(40):
    print(i, rec_fib(i))

เรียกซ้ำการเรียกคืนอย่างมีประสิทธิภาพ

สามารถบันทึกเพื่อปรับปรุงความเร็ว (ตัวอย่างนี้ใช้ประโยชน์จากข้อเท็จจริงที่ว่าอาร์กิวเมนต์คำหลักเริ่มต้นเป็นวัตถุเดียวกันทุกครั้งที่มีการเรียกใช้ฟังก์ชัน แต่โดยปกติแล้วคุณจะไม่ใช้อาร์กิวเมนต์เริ่มต้นที่ไม่แน่นอนด้วยเหตุผลนี้):

def mem_fib(n, _cache={}):
    '''efficiently memoized recursive function, returns a Fibonacci number'''
    if n in _cache:
        return _cache[n]
    elif n > 1:
        return _cache.setdefault(n, mem_fib(n-1) + mem_fib(n-2))
    return n

คุณจะพบว่ารุ่นที่บันทึกได้นั้นเร็วกว่ามากและจะเกินความลึกการเรียกซ้ำสูงสุดของคุณอย่างรวดเร็วก่อนที่คุณจะนึกถึงว่าจะลุกขึ้นดื่มกาแฟ คุณสามารถดูได้เร็วขึ้นด้วยการทำสิ่งนี้:

for i in range(40):
    print(i, mem_fib(i))

(อาจดูเหมือนว่าเราสามารถทำด้านล่าง แต่จริง ๆ แล้วไม่ให้เราใช้ประโยชน์จากแคชเพราะมันเรียกตัวเองก่อนที่จะเรียก setdefault)

def mem_fib(n, _cache={}):
    '''don't do this'''
    if n > 1:  
        return _cache.setdefault(n, mem_fib(n-1) + mem_fib(n-2))
    return n

ตัวกำเนิดที่กำหนดซ้ำ:

เมื่อฉันได้เรียนรู้ Haskell ฉันได้พบกับการดำเนินการใน Haskell นี้:

fib@(0:tfib) = 0:1: zipWith (+) fib tfib

ใกล้เคียงที่สุดที่ฉันคิดว่าฉันจะได้รับสิ่งนี้ใน Python ในขณะนี้คือ:

from itertools import tee

def fib():
    yield 0
    yield 1
    # tee required, else with two fib()'s algorithm becomes quadratic
    f, tf = tee(fib()) 
    next(tf)
    for a, b in zip(f, tf):
        yield a + b

นี่แสดงให้เห็นว่า:

[f for _, f in zip(range(999), fib())]

แม้ว่าสามารถทำได้ถึงขีด จำกัด การเรียกซ้ำเท่านั้น โดยปกติแล้ว 1,000 ในขณะที่รุ่น Haskell สามารถสูงถึง 100s ล้านแม้ว่ามันจะใช้หน่วยความจำแล็ปท็อปของฉันทั้งหมด 8 GB ในการทำเช่นนั้น:

> length $ take 100000000 fib 
100000000

การใช้ตัววนซ้ำเพื่อรับหมายเลขฟีโบนักชีที่ n

ผู้วิจารณ์ถามว่า:

คำถามสำหรับฟังก์ชั่นตอแหล () ซึ่งใช้ตัววนซ้ำ: ถ้าคุณต้องการได้ลำดับที่ n เช่นหมายเลขตอแหลที่ 10?

เอกสารประกอบ itertools มีสูตรสำหรับสิ่งนี้:

from itertools import islice

def nth(iterable, n, default=None):
    "Returns the nth item or a default value"
    return next(islice(iterable, n, None), default)

และตอนนี้:

>>> nth(fib(), 10)
55

เกี่ยวกับตัวเลือกสุดท้าย '' 'อย่าทำแบบนี้' '' ฉันไม่เข้าใจว่าทำไมมันถึงเรียกตัวเองก่อน setdefault setdefault ไม่ควรส่งคืนค่าถ้า n เป็นคีย์ที่ถูกต้องหรือไม่ Doc กล่าวว่า "หากคีย์อยู่ในพจนานุกรมให้คืนค่าถ้าไม่ให้ใส่รหัสด้วยค่าเริ่มต้นและคืนค่าเริ่มต้นค่าเริ่มต้นเป็น" ไม่มี " ฉันพลาดอะไรไป
binithb

@ binithb นิพจน์ภายในการsetdefaultโทรถูกประเมินก่อน setdefaultคือ
Aaron Hall


21

แนวคิดที่อยู่เบื้องหลังลำดับฟีโบนักชีแสดงในรหัสไพ ธ อนต่อไปนี้:

def fib(n):
   if n == 1:
      return 1
   elif n == 0:   
      return 0            
   else:                      
      return fib(n-1) + fib(n-2)         

ซึ่งหมายความว่า Fib เป็นฟังก์ชันที่สามารถทำหนึ่งในสามสิ่ง มันกำหนด fib (1) == 1, fib (0) == 0, และ fib (n) เป็น:

ตอแหล (n-1) + ตอแหล (n-2)

โดยที่ n เป็นจำนวนเต็มตามอำเภอใจ ซึ่งหมายความว่าตัวอย่างเช่นตอแหล (2) จะขยายออกไปเป็นเลขคณิตต่อไปนี้:

fib(2) = fib(1) + fib(0)
fib(1) = 1
fib(0) = 0
# Therefore by substitution:
fib(2) = 1 + 0
fib(2) = 1

เราสามารถคำนวณ Fib (3) ได้ในลักษณะเดียวกันกับเลขคณิตที่แสดงด้านล่าง:

fib(3) = fib(2) + fib(1)
fib(2) = fib(1) + fib(0)
fib(2) = 1
fib(1) = 1
fib(0) = 0
# Therefore by substitution:
fib(3) = 1 + 1 + 0

สิ่งสำคัญที่ต้องตระหนักในที่นี้คือไม่สามารถคำนวณ fib (3) โดยไม่ต้องคำนวณ fib (2) ซึ่งคำนวณได้จากการรู้คำจำกัดความของ fib (1) และ fib (0) การมีฟังก์ชั่นเรียกตัวเองว่าฟังก์ชั่นฟีโบนักชีเรียกว่าการเรียกซ้ำ (recursion) และเป็นหัวข้อสำคัญในการเขียนโปรแกรม

ดูเหมือนว่าจะเป็นการมอบหมายการบ้านดังนั้นฉันจะไม่ทำส่วนเริ่มต้น / สิ้นสุดให้คุณ Python เป็นภาษาที่แสดงออกอย่างมหัศจรรย์สำหรับเรื่องนี้ดังนั้นนี่ควรจะสมเหตุสมผลถ้าคุณเข้าใจคณิตศาสตร์และหวังว่าจะสอนคุณเกี่ยวกับการเรียกซ้ำ โชคดี!

แก้ไข: การวิจารณ์ที่เป็นไปได้อย่างหนึ่งของรหัสของฉันคือมันไม่ได้ใช้ฟังก์ชัน Python ที่สะดวกสบายซึ่งให้ฟังก์ชั่น fib (n) สั้นกว่ามาก ตัวอย่างของฉันค่อนข้างธรรมดากว่านิดหน่อยเนื่องจากภาษานอกหลามไม่ได้ให้ผล


นี่ไม่ใช่ปัญหาการบ้าน แต่ขอบคุณสำหรับคำตอบ! ฉันเข้าใจสิ่งที่ฉันต้องทำ แต่การเริ่มต้นและการใช้งานเป็นสิ่งที่ฉันติดอยู่ในตอนนี้ (โดยเฉพาะอย่างยิ่งกับการใช้ค่าอินพุตของผู้ใช้) คุณสามารถให้ข้อมูลเชิงลึกเกี่ยวกับเรื่องนี้หรือไม่? ฉันได้รับข้อผิดพลาด <function fib ที่ 0x0141FAF0>
SD

ฉันเข้าใจว่าคุณกำลังพยายามอย่างหนักที่จะใช้โปรแกรมที่อาจเกินความสามารถในปัจจุบันของคุณ ให้ฉันเขียนโค้ดเพิ่มเติมจะไม่ช่วยคุณ คุณควรพยายามแฮ็คโค้ดของฉันจนกว่ามันจะใช้งานได้และอ่านบทเรียนเพิ่มเติมของ Python ช่องว่างอาจมีปัญหา แต่ฉันไม่ทราบข้อผิดพลาดนั้น
James Thompson

ฉันเข้าใจ. มีความคิดอื่น ๆ ที่คุณคิดว่าฉันอาจหายไป? ฉันเข้าใจถ้าคุณไม่สามารถช่วยได้ ฉันขอขอบคุณสำหรับเวลาของคุณ
SD

ข้อผิดพลาด <function fib ที่ 0x0141FAF0> ของคุณอาจเป็นผลมาจากการพูดว่า "fib" (ซึ่งหมายถึงฟังก์ชันเอง) แทน "fib ()" ซึ่งจะเรียกใช้ฟังก์ชัน ขอให้โชคดี
Kiv

8
โปรดจำไว้ว่าวิธีการคำนวณซ้ำแบบไร้เดียงสาของการคำนวณจำนวนฟีโบนัชชีสามารถเข้าสู่สแต็คล้นได้ สำหรับวัตถุประสงค์ในทางปฏิบัติให้สร้างซ้ำ ๆ หรือใช้การจำบางอย่างหรือบางอย่าง
David Thornley

12

ความซับซ้อนของเวลา:

คุณสมบัติแคชช่วยลดวิธีการคำนวณอนุกรม Fibonacci จากO (2 ^ n)เป็นO (n)โดยการกำจัดการทำซ้ำในแผนภูมิแบบเรียกซ้ำของ Fibonacci:

ป้อนคำอธิบายรูปภาพที่นี่

รหัส:

import sys

table = [0]*1000

def FastFib(n):
    if n<=1:
        return n
    else:
        if(table[n-1]==0):
            table[n-1] = FastFib(n-1)
        if(table[n-2]==0):
            table[n-2] = FastFib(n-2)
        table[n] = table[n-1] + table[n-2]
        return table[n]

def main():
    print('Enter a number : ')
    num = int(sys.stdin.readline())
    print(FastFib(num))

if __name__=='__main__':
    main()

9

สิ่งนี้ค่อนข้างมีประสิทธิภาพโดยใช้ O (log n) การดำเนินการทางคณิตศาสตร์ขั้นพื้นฐาน

def fib(n):
    return pow(2 << n, n + 1, (4 << 2*n) - (2 << n) - 1) % (2 << n)

อันนี้ใช้การดำเนินการทางคณิตศาสตร์ขั้นพื้นฐาน O (1) แต่ขนาดของผลลัพธ์กลางมีขนาดใหญ่และดังนั้นจึงไม่มีประสิทธิภาพ

def fib(n):
    return (4 << n*(3+n)) // ((4 << 2*n) - (2 << n) - 1) & ((2 << n) - 1)

อันนี้คำนวณ X ^ n ในวงแหวนพหุนาม Z [X] / (X ^ 2 - X - 1) โดยใช้การยกกำลังด้วยการยกกำลังสอง ผลลัพธ์ของการคำนวณนั้นคือพหุนาม Fib (n) X + Fib (n-1) ซึ่งสามารถอ่านหมายเลขฟีโบนักชีที่ n ได้

อีกครั้งนี้ใช้การดำเนินการทางคณิตศาสตร์ O (log n) และมีประสิทธิภาพมาก

def mul(a, b):
        return a[0]*b[1]+a[1]*b[0]+a[0]*b[0], a[0]*b[0]+a[1]*b[1]

def fib(n):
        x, r = (1, 0), (0, 1)
        while n:
                if n & 1: r = mul(r, x)
                x = mul(x, x)
                n >>= 1
        return r[0]

1
เทคนิคที่หนึ่งและสามเป็นสิ่งที่ดี เทคนิคที่สองปิดโดย 1; จำเป็นต้องn -= 1ทำงานอย่างมีประสิทธิภาพและไม่สามารถทำงานn = 0ได้ ไม่ว่าในกรณีใดมันจะช่วยฉันได้จริงหากมีการเพิ่มบริบทมากมายเพื่ออธิบายว่าสิ่งเหล่านี้ทำงานอย่างไรโดยเฉพาะอย่างยิ่งเทคนิคแรก ฉันเห็นว่าคุณมีโพสต์ที่paulhankin.github.io/Fibonacci
คิวเมนตัส

6

รหัส Canonical Python เพื่อพิมพ์ลำดับ Fibonacci:

a,b=1,1
while True:
  print a,
  a,b=b,a+b       # Could also use b=a+b;a=b-a

สำหรับปัญหา "พิมพ์หมายเลข Fibonacci แรกที่ยาวกว่า 1,000 หลัก":

a,b=1,1
i=1
while len(str(a))<=1000:
  i=i+1
  a,b=b,a+b

print i,len(str(a)),a

4

เรารู้ว่า

ป้อนคำอธิบายรูปภาพที่นี่

และพลังที่ n ของเมทริกซ์นั้นให้เรา:

ป้อนคำอธิบายรูปภาพที่นี่

ดังนั้นเราสามารถใช้ฟังก์ชันที่คำนวณพลังของเมทริกซ์นั้นกับกำลัง n-th -1

เท่าที่เรารู้พลัง a ^ n เท่ากับ

ป้อนคำอธิบายรูปภาพที่นี่

ดังนั้นในตอนท้ายฟังก์ชั่นฟีโบนักชีจะเป็น O (n) ... ไม่มีอะไรแตกต่างไปจากการใช้งานที่ง่ายขึ้นถ้ามันไม่ได้เป็นเพราะเรารู้ด้วยเช่นกันx^n * x^n = x^2nและการประเมินของx^nสามารถทำได้ด้วยความซับซ้อน O (log n) )

นี่คือการใช้งานฟีโบนักชีของฉันโดยใช้ภาษาโปรแกรมอย่างรวดเร็ว:

struct Mat {
    var m00: Int
    var m01: Int
    var m10: Int
    var m11: Int
}

func pow(m: Mat, n: Int) -> Mat {
    guard n > 1 else { return m }
    let temp = pow(m: m, n: n/2)

    var result = matMultiply(a: temp, b: temp)
    if n%2 != 0 {
        result = matMultiply(a: result, b: Mat(m00: 1, m01: 1, m10: 1, m11: 0))
    }
    return result
}

func matMultiply(a: Mat, b: Mat) -> Mat {
    let m00 = a.m00 * b.m00 + a.m01 * b.m10
    let m01 = a.m00 * b.m01 + a.m01 * b.m11
    let m10 = a.m10 * b.m00 + a.m11 * b.m10
    let m11 = a.m10 * b.m01 + a.m11 * b.m11

    return Mat(m00: m00, m01: m01, m10: m10, m11: m11)
}

func fibonacciFast(n: Int) -> Int {

    guard n > 0 else { return 0 }
    let m = Mat(m00: 1, m01: 1, m10: 1, m11: 0)

    return pow(m: m, n: n-1).m00
}

สิ่งนี้มีความซับซ้อน O (บันทึก n) เราคำนวณoìpowerของ Q ด้วยเลขชี้กำลัง n-1 จากนั้นเราหาองค์ประกอบ m00 ซึ่งเป็น Fn + 1 ที่เลขชี้กำลังพลังงาน n-1 เป็นเลขฟีโบนักชี n-th ที่เราต้องการอย่างแท้จริง

เมื่อคุณมีฟังก์ชั่นฟีโบนักชีอย่างรวดเร็วคุณสามารถวนซ้ำจากหมายเลขเริ่มต้นและหมายเลขปลายทางเพื่อรับส่วนหนึ่งของลำดับฟีโบนักชีที่คุณสนใจ

let sequence = (start...end).map(fibonacciFast)

แน่นอนก่อนดำเนินการตรวจสอบบางอย่างเกี่ยวกับการเริ่มต้นและสิ้นสุดเพื่อให้แน่ใจว่าพวกเขาสามารถสร้างช่วงที่ถูกต้อง

ฉันรู้ว่าคำถามมีอายุ 8 ปี แต่ฉันก็สนุกกับการตอบคำถามอยู่ดี :)


3

1, 1, 2, 3, 5, 8, ...ลำดับฟีโบนักชีคือ:

นั่นคือf(1) = 1, f(2) = 1, f(3) = 2, ,...f(n) = f(n-1) + f(n-2)

การใช้งานที่ชื่นชอบ (ง่ายที่สุดและยังบรรลุความเร็วแสงเมื่อเปรียบเทียบกับการใช้งานอื่น ๆ ) คือ:

def fibonacci(n):
    a, b = 0, 1
    for _ in range(1, n):
        a, b = b, a + b
    return b

ทดสอบ

>>> [fibonacci(i) for i in range(1, 10)]
[1, 1, 2, 3, 5, 8, 13, 21, 34]

การจับเวลา

>>> %%time
>>> fibonacci(100**3)
CPU times: user 9.65 s, sys: 9.44 ms, total: 9.66 s
Wall time: 9.66 s

แก้ไข: การสร้างภาพตัวอย่างสำหรับการนำไปใช้นี้


3

ใช้การเรียกซ้ำ:

def fib(n):
    if n == 0:
        return 0
    elif n == 1:
        return 1
    else:
        return fib(n-1) + fib(n-2)
x=input('which fibonnaci do you want?')
print fib(x)

2

อีกวิธีในการทำ:

a,n=[0,1],10
map(lambda i: reduce(lambda x,y: a.append(x+y),a[-2:]),range(n-2))

การกำหนดรายการเป็น 'a' การกำหนดจำนวนเต็มให้กับ 'n' Map และการลดลงเป็น 2 ในสามฟังก์ชั่นที่ทรงพลังที่สุดในหลาม แผนที่นี้ใช้เพื่อทำซ้ำ 'n-2' ครั้ง a [-2:] จะได้รับสององค์ประกอบสุดท้ายของอาร์เรย์ a.append (x + y) จะเพิ่มสององค์ประกอบสุดท้ายและจะผนวกเข้ากับอาร์เรย์


1

สิ่งเหล่านี้ดูซับซ้อนกว่าที่พวกเขาต้องการ รหัสของฉันง่ายและรวดเร็วมาก:

def fibonacci(x):

    List = []
    f = 1
    List.append(f)
    List.append(f) #because the fibonacci sequence has two 1's at first
    while f<=x:
        f = List[-1] + List[-2]   #says that f = the sum of the last two f's in the series
        List.append(f)
    else:
        List.remove(List[-1])  #because the code lists the fibonacci number one past x. Not necessary, but defines the code better
        for i in range(0, len(List)):
        print List[i]  #prints it in series form instead of list form. Also not necessary

2
การเขียนโปรแกรมแบบไดนามิก FTW! fibonacci (1000000000000000000000000000000000000000000000000000000000000000000000000000000000) ตอบสนองเกือบจะทันที
Hans

6
ยังไงก็เถอะฉันสงสัยมัน
Lanaru

สิ่งที่เกี่ยวกับการเริ่มรายการเป็น [0, 1] (เช่น List.append (0); List.append (1)) เพื่อหลีกเลี่ยงคำสั่งลบหลังจากที่อื่น? ... และหมายเลขฟีโบนักชีน่าจะจัดทำดัชนีได้ดีกว่าเพราะฟีโบนักชี (10) ส่งคืนหมายเลขฟีโบนักชีต่ำกว่า 10 ไม่ใช่อันดับที่ 10
SeF

1

ตกลง .. หลังจากที่รู้สึกเหนื่อยกับการอ้างอิงคำตอบที่มีความยาวทั้งหมดตอนนี้ค้นหาวิธีการเรียงลำดับด้านล่าง & น่ารักตรงไปตรงมาสำหรับการใช้ Fibonacci ใน python คุณสามารถปรับปรุงมันในแบบที่คุณต้องการโดยรับอาร์กิวเมนต์หรือรับข้อมูลผู้ใช้ ... หรือเปลี่ยนขีด จำกัด จาก 10,000 ตามที่คุณต้องการ……

def fibonacci():
    start = 0 
    i = 1 
    lt = []
    lt.append(start)
    while start < 10000:
        start += i
        lt.append(start)
        i = sum(lt[-2:])
        lt.append(i)
    print "The Fibonaccii series: ", lt

วิธีการนี้ยังทำงานได้ดี ค้นหาการวิเคราะห์การทำงานด้านล่าง

In [10]: %timeit fibonacci
10000000 loops, best of 3: 26.3 ns per loop

1

นี่คือการปรับปรุงคำตอบของ mathew henry:

def fib(n):
    a = 0
    b = 1
    for i in range(1,n+1):
            c = a + b
            print b
            a = b
            b = c

รหัสควรพิมพ์ b แทนการพิมพ์ c

ผลลัพธ์: 1,1,2,3,5 ....


1

ใช้สำหรับลูปและพิมพ์เพียงผลลัพธ์

def fib(n:'upto n number')->int:
    if n==0:
        return 0
    elif n==1:
        return 1
    a=0
    b=1
    for i in range(0,n-1):
        b=a+b
        a=b-a
    return b

ผลลัพธ์

>>>fib(50)
12586269025
>>>>
>>> fib(100)
354224848179261915075
>>> 

พิมพ์listตัวเลขที่มีทั้งหมด

def fib(n:'upto n number')->int:
    l=[0,1]
    if n==0:
        return l[0]
    elif n==1:
        return l
    a=0
    b=1
    for i in range(0,n-1):
        b=a+b
        a=b-a
        l.append(b)
    return l

ผลลัพธ์

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

1
import time
start_time = time.time()



#recursive solution
def fib(x, y, upperLimit):
    return [x] + fib(y, (x+y), upperLimit) if x < upperLimit else [x]

#To test :

print(fib(0,1,40000000000000))
print("run time: " + str(time.time() - start_time))

ผล

[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946, 17711, 28657, 46368 , 75025, 121393, 196418, 317811, 514229, 832040, 1346269, 2178309, 3524578, 7707,979,986,979,986,979,986,979,436,779,986,986,986,986,986,986,986,986,986,986,986,986,986,968,986,986,986,986,910,968,986,989,966,968,989,966,968,446,446,446,438,440,438,440,432,438,432,438,432,438,432,438,432,438,432,438,432,438,440 , 12586269025, 20365011074, 32951280099, 53316291173, 86267571272, 139583862445, 225851433717, 365435296162, 591286729879, 956722026041, 1548008755920, 2504730781961, 4052739537881, 6557470319842, 10610209857723, 17167680177565, 27777890035288, 44945570212853]

เวลาทำงาน: 0.04298138618469238


1

มีวิธีที่ง่ายมากที่จะรู้ว่า!

คุณสามารถเรียกใช้รหัสนี้ออนไลน์ได้อย่างอิสระโดยใช้http://www.learnpython.org/

# Set the variable brian on line 3!

def fib(n):
"""This is documentation string for function. It'll be available by fib.__doc__()
Return a list containing the Fibonacci series up to n."""
result = []
a = 0
b = 1
while a < n:
    result.append(a)  # 0 1 1 2 3 5  8  (13) break
    tmp_var = b       # 1 1 2 3 5 8  13
    b = a + b         # 1 2 3 5 8 13 21
    a = tmp_var       # 1 1 2 3 5 8  13
    # print(a)
return result

print(fib(10))
# result should be this: [0, 1, 1, 2, 3, 5, 8]

วิธีที่ง่ายต่อการตระหนักถึงชุดฟีโบนักชีเพียงแค่ใช้ตัววนซ้ำโดยไม่มีโครงสร้างข้อมูลเรียกซ้ำที่ซับซ้อน!
xgqfrms

1

สามารถทำได้โดยวิธีต่อไปนี้

n = 0

ตัวเลข = [0]

สำหรับฉันอยู่ในช่วง (0,11):
    พิมพ์ n
    numbers.append (n)
    prev = ตัวเลข [-2]
    ถ้า n == 0:
        n = 1
    อื่น:
        n = n + ก่อนหน้า

1

เพื่อความสนุกสนานใน Python 3.8+ คุณสามารถใช้นิพจน์การมอบหมาย (หรือผู้ดำเนินการวอลรัส) ในรายการความเข้าใจเช่น:

>>> a, b = 0, 1
>>> [a, b] + [b := a + (a := b) for _ in range(8)]  # first 10 Fibonacci numbers
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

การแสดงออกที่ได้รับมอบหมายช่วยให้คุณสามารถกำหนดค่าให้กับตัวแปรและส่งกลับในการแสดงออกที่เหมือนกัน ดังนั้นการแสดงออก

b := a + (a := b)

เทียบเท่ากับการดำเนินการ

a, b = b, a + b

bและกลับมาค่าของ


0

15 นาทีในการสอนที่ฉันใช้เมื่อเรียนรู้ Python มันขอให้ผู้อ่านเขียนโปรแกรมที่จะคำนวณลำดับฟีโบนักชีจากหมายเลขอินพุต 3 ตัว (หมายเลขฟีโบนักชีแรกหมายเลขที่สองและเบอร์ที่จะหยุดลำดับ) บทช่วยสอนครอบคลุมเฉพาะตัวแปรถ้า / แล้วและวนซ้ำไปยังจุดนั้น ยังไม่มีฟังก์ชั่น ฉันมาพร้อมกับรหัสต่อไปนี้:

sum = 0
endingnumber = 1                

print "\n.:Fibonacci sequence:.\n"

firstnumber = input("Enter the first number: ")
secondnumber = input("Enter the second number: ")
endingnumber = input("Enter the number to stop at: ")

if secondnumber < firstnumber:

    print "\nSecond number must be bigger than the first number!!!\n"

else:

while sum <= endingnumber:

    print firstnumber

    if secondnumber > endingnumber:

        break

    else:

        print secondnumber
        sum = firstnumber + secondnumber
        firstnumber = sum
        secondnumber = secondnumber + sum

อย่างที่คุณเห็นมันไม่มีประสิทธิภาพจริงๆ แต่มันใช้ได้ผล


0
def fib():
    a,b = 1,1
    num=eval(input("Please input what Fib number you want to be calculated: "))
    num_int=int(num-2)
    for i in range (num_int):
        a,b=b,a+b
    print(b)

3
eval(input())ไม่ต้องการที่นี่ ฉันคิดว่าint(input())ในกรณีที่ดีกว่า
GingerPlusPlus

0

เพิ่งผ่านhttp://projecteuler.net/problem=2นี่คือสิ่งที่ฉันทำ

# Even Fibonacci numbers
# Problem 2

def get_fibonacci(size):
    numbers = [1,2]
    while size > len(numbers):
        next_fibonacci = numbers[-1]+numbers[-2]
        numbers.append(next_fibonacci)

    print numbers

get_fibonacci(20)

0
def fib(x, y, n):
    if n < 1: 
        return x, y, n
    else: 
        return fib(y, x + y, n - 1)

print fib(0, 1, 4)
(3, 5, 0)

#
def fib(x, y, n):
    if n > 1:
        for item in fib(y, x + y, n - 1):
            yield item
    yield x, y, n

f = fib(0, 1, 12)
f.next()
(89, 144, 1)
f.next()[0]
55


0

ตามลำดับฟีโบนัชชีคลาสสิคและเพื่อประโยชน์ของหนึ่งตอร์ปิโด

หากคุณต้องการจำนวนดัชนีคุณสามารถใช้การลด (แม้ว่าการลดจะไม่เหมาะที่สุดสำหรับสิ่งนี้มันเป็นการออกกำลังกายที่ดี)

def fibonacci(index):
    return reduce(lambda r,v: r.append(r[-1]+r[-2]) or (r.pop(0) and 0) or r , xrange(index), [0, 1])[1]

และเพื่อให้ได้อาร์เรย์ที่สมบูรณ์เพียงแค่ลบหรือ (r.pop (0) และ 0)

reduce(lambda r,v: r.append(r[-1]+r[-2]) or r , xrange(last_index), [0, 1])

0

แล้วอันนี้ละ? ฉันเดาว่ามันไม่แฟนซีเหมือนคำแนะนำอื่น ๆ เพราะมันต้องการสเปคเริ่มต้นของผลลัพธ์ก่อนหน้าเพื่อให้ได้ผลลัพธ์ที่คาดหวัง แต่ฉันรู้สึกว่าเป็นตัวเลือกที่อ่านได้มากเช่นทั้งหมดที่ทำคือให้ผลลัพธ์และผลลัพธ์ก่อนหน้า การสอบถามซ้ำ

#count the number of recursions
num_rec = 0

def fibonacci(num, prev, num_rec, cycles):

    num_rec = num_rec + 1

    if num == 0 and prev == 0:
        result  = 0;
        num = 1;
    else:
        result = num + prev

    print(result)

    if num_rec == cycles:
        print("done")
    else:
        fibonacci(result, num, num_rec, cycles)

#Run the fibonacci function 10 times
fibonacci(0, 0, num_rec, 10)

นี่คือผลลัพธ์:

0
1
1
2
3
5
8
13
21
34
done


0
def fib(lowerbound, upperbound):
    x = 0
    y = 1
    while x <= upperbound:
        if (x >= lowerbound):
            yield x
        x, y = y, x + y

startNumber = 10
endNumber = 100
for fib_sequence in fib(startNumber, endNumber):
    print "And the next number is... %d!" % fib_sequence

0

คำอธิบายโดยละเอียดเพิ่มเติมเกี่ยวกับการทำงานของการบันทึกสำหรับลำดับฟีโบนักชี

# Fibonacci sequence Memoization

fib_cache = {0:0, 1:1}

def fibonacci(n):
    if n < 0:
        return -1
    if fib_cache.has_key(n):
        print "Fibonacci sequence for %d = %d cached" % (n, fib_cache[n])
        return fib_cache[n]
    else:
        fib_cache[n] = fibonacci(n - 1) + fibonacci(n - 2)
    return fib_cache[n]

if __name__ == "__main__":
    print fibonacci(6)
    print fib_cache
    # fibonacci(7) reuses fibonacci(6) and fibonacci(5)
    print fibonacci(7)
    print fib_cache

0

ฉันพยายามหลีกเลี่ยงฟังก์ชันเรียกซ้ำเพื่อแก้ปัญหานี้ดังนั้นฉันจึงใช้วิธีวนซ้ำ เดิมทีฉันทำฟังก์ชั่นเรียกซ้ำที่บันทึกไว้ แต่ยังคงกดปุ่มวนซ้ำที่ลึกที่สุด ฉันยังมีเป้าหมายหน่วยความจำที่เข้มงวดดังนั้นคุณจะเห็นฉันเก็บอาร์เรย์เล็กที่สุดเท่าที่ฉันสามารถทำได้ในระหว่างกระบวนการวนลูปเพียงรักษาค่า 2-3 ในอาร์เรย์ตลอดเวลา

def fib(n):
    fibs = [1, 1] # my starting array
    for f in range(2, n):
        fibs.append(fibs[-1] + fibs[-2]) # appending the new fib number
        del fibs[0] # removing the oldest number
    return fibs[-1] # returning the newest fib

print(fib(6000000))

การได้หมายเลขฟีโบนัชชีที่ 6 ล้านใช้เวลาประมาณ 282 วินาทีบนเครื่องของฉันในขณะที่ฟีโบนัชชี 600k ใช้เวลาเพียง 2.8 วินาที ฉันไม่สามารถรับหมายเลขฟีโบนัชชีขนาดใหญ่ด้วยฟังก์ชั่นวนซ้ำได้

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