【问题标题】:An iterative algorithm for Fibonacci numbers斐波那契数的迭代算法
【发布时间】:2013-02-09 10:11:39
【问题描述】:

我对斐波那契数的迭代算法很感兴趣,所以我在 wiki 上找到了这个公式……它看起来很简单,所以我在 Python 中尝试了它……编译没有问题,而且公式看起来正确。 ..不知道为什么它给出了错误的输出......我没有正确实施它吗?

def fib (n): 
    if( n == 0):
        return 0
    else:
        x = 0
        y = 1
        for i in range(1,n):
            z = (x + y)
            x = y
            y = z
            return y

for i in range(10):
    print (fib(i))

输出

0

1
1
1
1
1
1

【问题讨论】:

  • 如果您对斐波那契数列算法的复杂性感兴趣,值得一看 post

标签: python algorithm fibonacci


【解决方案1】:

问题是您的return y 在您的函数循环内。所以在第一次迭代之后,它已经停止并返回第一个值:1。除非n为0,在这种情况下,函数返回0本身,如果n为1,当for 循环甚至不会迭代一次,并且没有正在执行 return(因此有 None 返回值)。

要解决此问题,只需将 return y 移出循环即可。

替代实现

按照 KebertX 的示例,这是我个人用 Python 制作的解决方案。当然,如果您要处理许多斐波那契值,您甚至可能希望将这两种解决方案结合起来并为这些数字创建一个缓存。

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

【讨论】:

  • @Adelin 那是什么语言?这是一个 Python 问题,而不是 Python 代码。考虑创建一个新问题,或在codereview.SE 上询问以查看您的代码。话虽如此,您的数组大小对于 limit=1 是错误的,这会给您一个索引异常。
  • 在脚本末尾返回 a 是计算 f(n - 1) 而不是 f(n)。您应该返回 b 以返回 f(n)
  • @eton_ceb 这取决于您对Fibonacci sequence 的定义。我通常以01 而不是11 开始序列。
  • 你可以忽略i,直接写for _ in range(n)
  • 我会做 2 处更改:(1) :我们可以用return b 代替return a,然后我们可以少循环一次并得到答案。 (2):使用for i in range(2, n+1): 代替for i in range(0, n):,因此i 将代表fib(b) 的实际fib 计算。最后,缓存是不必要的,无论如何我们每一轮都在做 O(1) 时间复杂度。干杯。
【解决方案2】:

在 fib(0) 上,您返回 0,因为:

if (n == 0) {
    return 0;
}

在 fib(1) 上,您返回 1,因为:

y = 1
return y

在 fig(2) 上,您返回 1 是因为:

y = 1
return y

...等等。只要return y 在您的循环中,该函数每次都会在您的 for 循环的第一次迭代时结束。

这是另一个用户想出的一个很好的解决方案: How to write the Fibonacci Sequence in Python

【讨论】:

  • (不管那些花括号是从哪里来的……from __future__ import braces?:P)
【解决方案3】:

您在循环中返回一个值,因此函数在 y 的值大于 1 之前退出。

如果我可以建议一些更短、更 Python 的东西:

def fibs(n):                                                                                                 
    fibs = [0, 1, 1]                                                                                           
    for f in range(2, n):                                                                                      
        fibs.append(fibs[-1] + fibs[-2])                                                                         
    return fibs[n]

这将与您的算法完全相同,但不是创建三个临时变量,而是将它们添加到列表中,并按索引返回第 n 个斐波那契数。

【讨论】:

  • 这将占用更多内存,因为它需要将它们全部保留在列表中(您会注意到它对于 very large n)。我也不认为这是最好的 Pythonic 解决方案。我认为在一个简单的 for 循环中使用元组(取消)打包(请参阅我的答案的编辑)会更好。
  • 我会更进一步说,虽然这个解决方案是迭代的,但它与递归解决方案有相同的缺点,因为它不能在恒定空间中运行。您刚刚用列表元素替换了堆栈帧。
  • @KebertX 我知道这个线程是旧的,但为什么 a,b = b,a+b 在 for 循环中工作,而不是当你这样写 a=bb = a+b 时?我的意思是a,b = b,a+b 只是a = bb = a+b 对吗?
  • @HalcyonAbrahamRamirez:元组赋值与将每个右侧表达式依次分配给其各自的“变量”相同:使用元组赋值,最后一次评估在第一次之前完成分配 - 考虑交换:a, b = b, a
  • 这是一个递归解决方案,原始问题正在寻找一个迭代解决方案
【解决方案4】:

假设斐波那契数列的这些值:

F(0) = 0;

F(1) = 1;

F(2) = 1;

F(3) = 2

对于 N > 2 的值,我们将使用以下公式计算斐波那契值:

F(N) = F(N-1) + F(N-2)

我们可以采取的一种迭代方法是计算从 N = 0 到 N = Target_N 的斐波那契,这样我们就可以跟踪 N-1 和 N-2 的斐波那契的先前结果

public int Fibonacci(int N)
{
    // If N is zero return zero
    if(N == 0)
    {
        return 0;
    }

    // If the value of N is one or two return 1
    if( N == 1 || N == 2)
    {
       return 1;
    }

    // Keep track of the fibonacci values for N-1 and N-2
    int N_1 = 1;
    int N_2 = 1;

    // From the bottom-up calculate all the fibonacci values until you 
    // reach the N-1 and N-2 values of the target Fibonacci(N)
    for(int i =3; i < N; i++)
    {
       int temp = N_2;
       N_2 = N_2 + N_1;
       N_1 = temp;
    }

    return N_1 + N_2; 
}

【讨论】:

    【解决方案5】:
    def fibiter(n):
        f1=1
        f2=1
        tmp=int()
        for i in range(1,int(n)-1):
            tmp = f1+f2
            f1=f2
            f2=tmp
        return f2
    

    或并行分配:

    def fibiter(n):
        f1=1
        f2=1
        for i in range(1,int(n)-1):
            f1,f2=f2,f1+f2
        return f2
    

    打印光纤(4)

    【讨论】:

      【解决方案6】:
      import time
      
      a,b=0,1
      def fibton(n):
          if n==1:
              time.clock()
              return 0,time.clock()
          elif n==2:
              time.clock()
              return 1,time.clock()
          elif n%2==0:
              read="b"
          elif n%2==1:
              read="a"
          else:
              time.clock()
              for i in range(1,int(n/2)):
                  a,b=a+b,a+b
              if read=="b":
                  return b,time.clock()
              elif read=="a":
                  return.a,time.clock()
      

      免责声明:我目前使用的是移动设备,这可能并不完全正确

      这个算法利用了其他一些人的差距,现在它的速度实际上是原来的两倍。而不是只设置b 等于a 或反之亦然,然后将a 设置为a+b,我只用了两个字符就做了两次。我还根据我的其他迭代算法的运行情况添加了速度测试。这应该能够在一秒钟内达到大约第 200,000 个斐波那契数。它还返回数字的长度而不是整数,这将花费很长时间。

      我的另一个可以转到第二个斐波那契数,如内置时钟所示:在 10^-6 秒内。这个可以在大约 5^-6 内完成。我将很快获得一些更高级的算法,并以最快的速度对其进行改进。

      【讨论】:

      • 这应该怎么做?我的python环境似乎没有比我更多的线索。
      【解决方案7】:

      我在another thread 上遇到了这个问题,它比我尝试过的任何其他方法都要快得多,并且不会在大量数据上超时。这是数学的link

      def fib(n):
          v1, v2, v3 = 1, 1, 0  
          for rec in bin(n)[3:]: 
              calc = v2*v2
              v1, v2, v3 = v1*v1+calc, (v1+v3)*v2, calc+v3*v3
              if rec=='1':    v1, v2, v3 = v1+v2, v1, v2
          return v2
      

      【讨论】:

        【解决方案8】:

        这项工作(直观

        def fib(n):
            if n < 2:
                return n
            o,i = 0,1
            while n > 1:
                g = i
                i = o + i
                o = g
                n -= 1
            return i
        

        【讨论】:

        • 这个回答did I not implement it right ? 吗? (我觉得poke's code 直观,并且“倒计时n 手动”很烦人。)
        • @greybeard 谁在问did I not implement it right?? (倒计时有什么问题,Python允许它为什么不使用它?!)
        • Who's asking… [user:Ris] 是(在这个问题的最后一句话中)。在我看来,倒计时并没有错——我在评论中强调了手动(使用显式表达式、赋值、条件……),我不认为它是pythonesque*/*蟒蛇。它可避免的冗长。
        • 我明白你的意思,但我不是一个 python 人,那是一个想法(算法),只是用 python 表达它(仅此而已),——在阅读 sicp 时......
        【解决方案9】:

        这个简单但最快的方法怎么样......(我刚刚发现!)

        def fib(n):
            x = [0,1]
            for i in range(n >> 1):
                x[0] += x[1]
                x[1] += x[0]
            return x[n % 2]
        

        注意!结果,这个简单的算法只使用了1个赋值和1个加法,因为循环长度缩短为1/2,每个循环包括2个赋值和2个加法。

        【讨论】:

        • 我看不到 "the a-b-formulation" 的改进。 fastest way你知道approaches using O(log n) iterations吗?
        • 正确的,其他ab结构中的赋值数是3*n,因为包含了一个隐藏的赋值(任何swap之类的问题都无法避免这个顺序:temp = a,a = a+ b, b = 温度)。所以我可以说我的建议是更快的方式。实际上,我测试和检查结果的速度比其他 a-b 形式快 2 倍或 3 倍。你能推荐斐波那契问题中的任何 O(log n) 算法吗?
        【解决方案10】:
        fcount = 0 #a count recording the number of Fibonacci numbers generated
        prev = 0
        current = 0
        next = 1
        ll = 0 #lower limit
        ul = 999 #upper limit
        
        while ul < 100000:
            print("The following Fibonacci numbers make up the chunk between %d and %d." % (ll, ul))
            while next <= ul:
                print(next)
                prev = current
                current = next
                next = prev + current
                fcount += 1 #increments count
        
            print("Number of Fibonacci numbers between %d and %d is %d. \n" % (ll, ul, fcount))        
            ll = ul + 1 #current upper limit, plus 1, becomes new lower limit
            ul += 1000 #add 1000 for the new upper limit
            fcount = 0 #set count to zero for a new batch of 1000 numbers
        

        【讨论】:

          【解决方案11】:

          python中的非递归斐波那契数列

          def fibs(n):
              f = []
              a = 0
              b = 1
              if n == 0 or n == 1:
                  print n
              else:
                  f.append(a)
                  f.append(b)
                  while len(f) != n:
                      temp = a + b
                      f.append(temp)
                      a = b
                      b = temp
          
              print f
          
          fibs(10)
          

          输出: [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

          【讨论】:

          • 这个回答did I not implement it right ? 吗?
          • 斐波那契数列值:0、1、1、2、3、5、8、13、21、34、55、89、144、233、377、610、987、1597、2584、 4181, 6765, 10946, 17711,.....请将您的输出值与此值进行比较
          • 我没有输出。我碰巧认识OEIS A000045,并成为尝试在 17 年 1 月改进 2013 年 2 月问题的演示的人。
          【解决方案12】:

          可能的解决方案:

          a=0
          b=1
          d=[a,b]
          n=int(input("Enter a number"))
          i=0
          while len(d)<n:
              temp=a+b
              d.append(temp)
              a=temp
              b=d[i+1]
              i+=1
          print("Fibonacci series of {} is {}".format(n,d))  
          

          【讨论】:

          • 这个怎么回答did I not implement it right ?
          【解决方案13】:

          另一种可能的方法:

          a=0
          b=1
          d=[a,b]
          n=int(input("Enter a number"))
          i=2
          while i<n:
              e=d[-1]+d[-2]
              d.append(e)
              i+=1
          print("Fibonacci series of {} is {}".format(n,d))
          

          【讨论】:

          • 虽然此代码有效,但它似乎解决的问题与提问者所问的问题不同。您正在计算斐波那契数列中所有第一个 n 值的列表,而它们的函数只计算 nth 值。没有必要为此使用O(n) 内存。而且我真的不明白你为什么回答了两次,每次的代码都非常相似。如果您认为有多种有用的算法,您可以将它们都发布在同一个答案中。
          猜你喜欢
          • 2016-02-19
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-01-18
          • 2018-08-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多