使用一种非常不优雅的方式解决斐波那契数列
题目:
一位朋友做了一道挺简单ACM的题目,大概的意思就是下面这样的
你在第一级台阶上,每次可以往上跳一级或者两级,如果台阶的高度为n问有多少种跳法。
这道题一上手就被想复杂了,嗯,有多少种跳法,这不就是排列组合的问题么,求出每次的跳跃可以分解成多少个1或者2然后针对分解的列表进行排列组合再累加起来*就是结果了,现在想一下当时的脑洞真的是太大了,或者说根本就没有想过这个问题有没有更加简便的解法,于是就去写代码了,写出来的代码就是这个鬼样子的:
# -*- coding: utf-8 -*-
#使用一种非常不优雅的方式解决斐波那契数列=。=
class steppy(object):
def __init__(self, num):
self.num = num
def step(self):
tmp = 0
#只有一个台阶的情况
if self.num == 1:
tmp += 1
return tmp
else:
for list in self._getdilist():
tmp += self.cacul(list)
return tmp
def _getdilist(self):
for i in range(self.num):
temp = self.num - i*2
if temp >= 0:
yield [i, temp]
#排列组合
def cacul(self, list):
tmp = 0
if list[0]==0 or list[1] ==0:
return 1
else:
sum = list[0] + list[1]
return self.f(sum)/(self.f(list[0])*self.f(sum - list[0]))
def f(self, num):
n = num
tmp = 1
while n>0:
tmp = tmp*n
n = n-1
return tmp
if __name__ == "__main__":
#inum = input('num:')
for inum in range(40):
obj = steppy(inum)
print(obj.step())
以上代码输出来没啥问题,但是,太复杂了有木有?!虽然ACM只是偶尔玩一下但是这样写代码别人写完了十道题可能你还在这道题目上墨迹,所以一定有更好的方法可以解决这个问题。
分析
自己想不出来的时候就去网上看大神分析,说到底在开始写这道题的时候还跟实验室的一个朋友争论来着,说这道题能不能用递归解决,我当时觉得不能,当时觉得你这个每次走一步或者两步怎么去写公式嘛!(骚年你还是too young too naive)他居然觉得很有道理,然后递归的方案就被否决了。其实这道题的分析是这样的,借用我那朋友的博客解释一下:
到第n级台阶有两种方法,即在第n-1级处上1级,在第n-2级处上2级
这特么不就是斐波那契么?!!!
于是递归的方法也来了:
#-*- coding:utf-8 -*-
def step(n):
if n <= 1:
return 1
else:
return step(n - 1) + step( n - 2)
if __name__ == "__main__":
for inum in range(40):
print step(inum)
当时我的朋友是用C++写的,写完了丢去oj,问题又来了,代码没问题,但是,太慢了!!!C++应该很快吧啊喂~我这个代码是python的,跑到5702887的时候数字基本上是一个一个爬出来的,很明显的延迟啊有木有?!这样丢上去ojoj个球啊,不行,还得改。
改进
然后我的朋友就蛋碎一地,不知道怎么改,我说要不就做个数组吧,预定义几个值然后需要的话一个一个加就好了,实验室的朋友说这个不行吧,然后半信半疑地敲完了代码,提交上去,成功了==,然后他就炸了,去搜别人的oj代码,发现差不多都是这样的,嗯于是他怀疑了一上午的人生。最后贴上最终代码:
def calc(n):
if n <= 2:
return 1
else:
a = [0] * n
a[0] = 1
a[1] = 1
tmp = 1
for i in range(n):
if i < 1:
tmp += a[i]
else:
a[i] = a[i - 1] + a[i - 2]
tmp += a[i]
return tmp
if __name__ == "__main__":
n = input()
print calc(n)
话说Python的for不能从第二个开始真的挺蛋疼的,代码写得有点乱因为好困qwq