我在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
你可以帮我解决一下吗?
答案 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) == 0
,fib(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
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
),您需要返回1
或fib3(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&&)