Python|每日一练|斐波那契数列|优化算法|迭代|动态计算|排列组合|时间复杂度:走楼梯

文章讨论了一种优化斐波那契数列算法以解决走楼梯问题,通过动态规划减少计算量,提高效率。对于给定的楼梯阶数n,计算走到n阶的不同方案数,原基础实现由于递归导致超时,改进后的动态规划方法在n-1次迭代内完成计算,避免了重复计算,提高了运行速度。
摘要由CSDN通过智能技术生成

题目名称:走楼梯

时间限制:1000ms内存限制:256M

题目描述

现在有一截楼梯,根据你的腿长,你一次能走 1 级或 2 级楼梯,已知你要走 n 级楼梯才能走到你的目的楼层,请实现一个方法,计算你走到目的楼层的方案数。(测试用例仅做参考,我们会根据代码质量进行评分)

输入描述:

输入整数n(1<=n<=50)

输出描述:

输出方案数。

示例 

示例1

输入5

输出8

提示

思路说明:

你一次能走 1 级或 2 级楼梯,已知你要走 n 级楼梯才能走到你的目的楼层,则设F(n)为走到n阶的种数,则F(n)=F(n-1)+F(n-2)。

当n=1时,F(1)=1,n=2时,F(2)=2, F(3)=4,…符合斐波那契数列的特征。

斐波那契数列(百度百科)

斐波那契数列(Fibonacci sequence),又称黄金分割数列,因数学家莱昂纳多·斐波那契(Leonardo Fibonacci)以兔子繁殖为例子而引入,故又称为兔子数列,指的是这样一个数列:112358132134……在数学上,斐波那契数列以如下被以递推的方法定义:F(0)=0F(1)=1, F(n)=F(n - 1)+F(n - 2)n ≥ 2n N*

基础实现代码:

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

if __name__ == "__main__":

    n = int(input().strip())
    ways = f(n)
    print(int(ways))

问题:

但该方法不能通过系统测试,未能在规定时间内运行结束。

算法需优化。

改进:动态计算

引自:Python学习教程:算法如何解决楼梯台阶问题_千锋python和唐唐的博客-CSDN博客_python中关于台阶的走法

在函数体内实现了迭代,每个循环只计算第n – 1n-2,不是整个函数去迭代,且只计算n-1次,不重复计算。

代码:

def fibonacci(n):
    a, b = 1, 2
    #每次只计算第n – 1和n-2,不是整个函数去迭代,且只计算n-1次,不重复计算。
    for _ in range(n - 1):
        a, b = b, a + b
    return a


if __name__ == "__main__":
    n = int(input().strip())

    ways = fibonacci(n)
    print(int(ways))

思路2:排列组合方法

引自:爬楼梯算法的数学思路_shangjun2018的博客-CSDN博客_爬台阶算法

走了n-1个1和一个2时,它的方法总数其实应该是:

sum = 1 + Cnk(n-1, 1) + Cnk(n-2, 2) + … Cnk(n/2 , n/2) 偶数情况。

sum = 1 + Cnk(n-1, 1) + Cnk(n-2, 2) + … Cnk(n//2 + 1 , n//2 - 1) 奇数情况。

注: n//2 为: 用n整除2, 然后取得的数向下取整。 (2.1取2, 2.9取2)

实现代码:

def computer(n):
    all_ways = 1
    if n % 2 == 0:
        stop_num = int(n / 2)
        for i in range(1, stop_num + 1):
            all_ways += Cnk(n - i, i)
    if n % 2 == 1:
        stop_num = (n // 2) + 1
        for i in range(1, stop_num + 1):
            all_ways += Cnk(n - i, i)
    return all_ways


def Cnk(n, k):
    value1 = 1
    for i in range(k):
        value1 = value1 * (n - i)

    value2 = 1
    for i in range(1, k + 1):
        value2 = value2 * i

    ans = value1 / value2
    return ans


if __name__ == "__main__":
    n = int(input().strip())

    ways = computer(n)
    print(int(ways))

扩展:步数:{集合X}

原文链接:https://blog.csdn.net/chen801090/article/details/100984687

从集合X中取步数的要求下爬楼梯。例如X = {1,3,5},那么我们的算法应该是f(n) = f(n – 1) + f(n – 3) + f(n – 5)。如果n <0,那么我们应该返回0,因为我们不能爬负数。

def staircase(n, X):

 if n < 0:
 return 0
 elif n == 0:
 return 1
 elif n in X:
 return 1 + sum(staircase(n - x, X) for x in X if x < n)
 else:
 return sum(staircase(n - x, X) for x in X if x < n)

这也很慢(O(|X|^N)),因为也重复计算了。

我们可以使用动态编程来加快速度。

每次的输入cache[i]将包含我们可以用集合X到达台阶i的方法的数量。然后,我们将使用与之前相同的递归从零开始构建数组:

def staircase(n, X):

     cache = [0 for _ in range(n + 1)]
     cache[0] = 1
     for i in range(n + 1):
         cache[i] += sum(cache[i - x] for x in X if i - x > 0)
         cache[i] += 1 if i in X else 0
     return cache[-1]

现在时间复杂度为O(N * |X|),空间复杂度为O(N)。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

打酱油的工程师

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值