Fibonacci在Python中的序列扭曲

时间:2017-04-30 20:58:57

标签: python recursion

我在Python中学习递归,现在我遇到了这个练习的问题:

  

请记住,Fibonacci的序列是一个数字序列,其中每个数字都是前两个数字的总和。

     

对于这个问题,递归地实现Fibonacci,扭曲!想象一下,我们想要创建一个名为Fibonacci-3的新数字序列。在Fibonacci-3中,序列中的每个数字都是前三个数字的总和。该   序列将以三个1开始,因此第四个Fibonacci-3   数字是3(1 + 1 + 1),第五个是5(1 + 1 + 3),第六个是9(1 + 3 + 5),第七个是17(3 + 5 + 9)等等。

     

将函数命名为fib3,并确保使用递归。

     

以下行将测试您的代码。

     

如果您的功能正确,他们将打印 1 3 17 57 。< / p>

print(fib3(3))
print(fib3(4))
print(fib3(7))
print(fib3(9))

这是迄今为止的代码:

def fib3(n):
    if n <= 1:
        return n
    else:
        return(fib3(n-1) + fib3(n-2) + fib3(n-3))

但结果是:1,2,11,37

你可以帮我解决一下吗?

4 个答案:

答案 0 :(得分:2)

其他人也在说同样的事情

正如其他人所说,您必须在1

时返回n <= 3
def fib3 (n):
  if n <= 3:
    return 1
  else:
    return fib3(n - 1) + fib3(n - 2) + fib3(n - 3)

print(fib3(3)) # 1
print(fib3(4)) # 3
print(fib3(7)) # 17
print(fib3(9)) # 57

...但你可以做得更好

fib3的定义是垃圾。它会进行疯狂的计算重复。例如,由于O(n 3 )复杂性,fib3(40)需要超过30分钟来计算

考虑使用带状态变量的辅助循环的方法 - O(n)复杂度允许它在小于1毫秒中计算相同的结果。

def fib3 (n):
  def aux (n,a,b,c):
    if n == 1:
      return a
    else:
      return aux(n-1,b,c,a+b+c)
  return aux(n,1,1,1)

print(fib3(3))  # 1
print(fib3(4))  # 3
print(fib3(7))  # 17
print(fib3(9))  # 57
print(fib3(40)) # 9129195487

Fibonacci作为通用程序:fibx

我们可以使生成斐波那契序列的整个过程变得通用,但首先我们必须使用fib3函数来解决这个问题。通常,Fibonacci numbers有第0个字词 - 即fib(0) == 0fib(1) == 1。在您的函数中,看起来第一个数字是fib3(1),其中fib3(0)会产生未定义的结果。

下面,我将介绍fibx,它可以使用任何二元运算符和任何种子值,并创建我们可以想象的任何斐波那契序列

from functools import reduce

def fibx (op, seed, n):
  [x,*xs] = seed
  if n == 0:
    return x
  else:
    return fibx(op, xs + [reduce(op, xs, x)], n - 1)

现在我们可以使用fibx使用add(+)运算符和种子值0,1

来实现标准的fibonacci
from operator import add

def fib (n):
  return fibx(add, [0,1], n)

print(fib(0)) # 0
print(fib(1)) # 1
print(fib(2)) # 1
print(fib(3)) # 2
print(fib(4)) # 3
print(fib(5)) # 5

使用fib3

实施fibx

我们可以使用与fibx运算符相同的add来实现您的fib3函数,但由于您的基于1的索引,请注意我正在抵消n用1来得到正确的输出

from operator import add

def fib3 (n):
  return fibx(add, [1,1,1], n-1)

print(fib3(3)) # 1
print(fib3(4)) # 3
print(fib3(7)) # 17
print(fib3(9)) # 57

我建议你从基于0的索引开始。这意味着从0开始的索引fib3(2)实际上等于基于1的索引fib3(3)

from operator import add

def fib3 (n):
  return fibx(add, [1,1,1], n)

print(fib3(2)) # 1
print(fib3(3)) # 3
print(fib3(6)) # 17
print(fib3(8)) # 57

使用fibx

的任何可以想象的序列

当然,你可以制作任何你能想象到的其他序列。在这里,我们weirdfib使用乘法(*)而非加法(+)来组合术语,并且起始种子为[1,2,3]

from operator import mul

def weirdfib (n):
  return fibx(mul, [1,2,3], n)

print(weirdfib(0)) # 1
print(weirdfib(1)) # 2
print(weirdfib(2)) # 3
print(weirdfib(3)) # 6
print(weirdfib(4)) # 36
print(weirdfib(5)) # 648
print(weirdfib(6)) # 139968

答案 1 :(得分:1)

您的问题说明会告诉您原因:

  

序列将从三个1开始

您的解决方案只返回100或更低版本的1

n == 1

这意味着对于if n <= 1: return n (仍应返回n == 2),您需要返回1fib3(2-1) + fib3(2-2) + fib3(2-3),这要归功于上述测试,然后触底以产生fib3(1) + fib3(0) + fib(-1) == 1 + 0 + -1

对于0,您将返回n == 3;我们在fib3(2) + fib3(1) + fib3(0) fib3(2)之上进行了研究,因此最终结果0是您观察到的0 + 1 + 0

最后,第4个1号码(fib3)不返回3,但n == 4 == fib3(3) + fib3(2) + fib3(1) == 1 + 0 + 1

更改2的第一次测试返回1,以修复系列中的前3个值:

n <= 3

现在代码通过了给定的测试:

def fib3(n):
    if n <= 3:
        return 1
    else:
        return fib3(n-1) + fib3(n-2) + fib3(n-3)

答案 2 :(得分:0)

如果n <= 1,情况比return n稍微复杂一些。

考虑n = 4的情况:您的递归调用将是fib(3)fib(2)fib(1)

lattermost立即返回1,这就是你想要的。但是,这两个递归调用做了一些奇怪的事情。 fib(2)递归到fib(1)fib(0)fib(-1),返回值基本上将大胖子fib(3)递归到fib(2) (我们看到的是0),fib(1)(有效,1),fib(0)(也是0)。

因此,您从一开始就获得1,并从fib(1)的递归fib(3)组件获得1。那是你的2!

基本上,您需要确保基本情况不能返回负数。修复(返回1或0),你应该是好的。作为Martijn Pieters mentioned,您还可以制作基本案例n <= 3,它应该达到同样的效果。

答案 3 :(得分:-1)

让我为最佳“pythonic”答案做出贡献。

重点是避免递归函数调用以优化代码的效率。 Pythonic思维方式将涉及以下紧凑代码,它是n个数字的Fibonacci序列的迭代创建,包括种子数[1,1,1]。

#define SPEC_MOVE(X) \
template<> inline \
typename std::remove_reference<X>::type&& move<X>(X t) noexcept \
{ \
  std::cout << "Invoke std::move() specialization\n"; \
  return static_cast<typename remove_reference<X>::type&&>(t); \
}
SPEC_MOVE(my_type&&)
SPEC_MOVE(my_type&)
SPEC_MOVE(my_type const&)
SPEC_MOVE(my_type const&&)
SPEC_MOVE(my_type const volatile&&)
SPEC_MOVE(my_type const volatile&)
SPEC_MOVE(my_type volatile&)
SPEC_MOVE(my_type volatile&&)