Python 斐波那契/跳台阶一步两步/跳台阶多种步法/配零钱

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/lnotime/article/details/82692848

Python3.6.3

 跳台阶一步两步

1.  跳n(n∈N)阶台阶过程中最多有 n//2 步是跳了2阶,2阶步数固定的情况下可以用 C(总步数, 2阶的步数) 求出方法数,再把所有情况都加起来即可。

from math import factorial
from functools import reduce
from scipy.special import comb  # C(N, k)


def f1(n):  # sum(C(总步数, n2) for n2 in range(max2))  # max2:2步的数量最大值
    return sum(comb(n-n2, n2, exact=True) for n2 in range(n//2 + 1))  # 速度比下一句快一个量级
    # return sum(reduce(lambda a, b: a*b, range(n2+1, n-n2+1) or [1]) // factorial(n- 2*n2) for n2 in range(n//2 + 1))

2. 动态规划:假设n(n∈N)阶台阶的跳法数为F(n),最后一步要么跳了2阶(前面跳了n-2个台阶,方法数为F(n-2) (n>=2) ),要么跳了1阶(前面跳了n-1个台阶,方法数是F(n-1) ),所以

                                                            F(n) = F(n-1) + F(n-2)    (n∈N,n>=2) ,

显然:

                                                            F(0) = 1,F(1) = 1 。

其实就是斐波那契数列(斐波那契数列通项公式中有无理数,用程序计算结果当n大于70时开始有误差,故不使用通项公式求法)。

关于F(0)=1: F(n)表示的是跳n阶台阶方法的数量,而不是跳了多少步。跳0阶,方法就是不跳,这是一个方法!(当然不同人不同看法,对程序影响其实不大)

斐波那契从前向后:

def f2(n):  # 1st
    if n < 2:
        return 1
    n0, n1 = 1, 1
    for _ in range(n-1):
        n0, n1 = n1, n0+n1
    return n1

斐波那契从后向前 n<=1996(与递归深度限制有关): 

def f3(n, cache=None):  # 2st
    cache = cache or {0: 1, 1: 1}  # 默认值为可变类型的参数
    t = cache.get(n)
    if t is not None:  
        return t  # 两个get不简化可以省空间,简化了省时间
    cache[n-2] = f3(n-2, cache)  # Python有递归深度限制,先算n-2比先算n-1能计算更大的n
    cache[n-1] = f3(n-1, cache)  # 两个赋值分开写比合着能计算的n可能更大(大1,也可能不大,因为最后一层可能是n-2,n-1都到边界也可能只有n-2到边界(与递归深度和边界有关))
    return cache[n-1] + cache[n-2]

检验:

def _test():
    for n in range(500):
        funcs = (f1, f2, f3)
        res = {f(n) for f in funcs}
        if len(res) != 1:
            print(n, [f(n) for f in funcs])
            break
        print(n, res.pop())
    else:
        print(True)


if __name__ == '__main__':
    _test()

n阶台阶,每次可以跳1阶、2阶、3阶、...、n阶

同样考虑最后那一步有n种情况,得到:

                                              F(n) = F(n-1) + F(n-2) + F(n-3) + ... + F(n-n)

                                                      = F(0) + F(1) + F(2) + ... + F(n-1)   (n∈N*)                          ①

所以:

                                           F(n-1) = F(0) + F(1) + F(2) + ... + F(n-2)   (n∈N,n>=2)                ②

① - ② 得:

                                                            F(n) = 2·F(n-1)   (n∈N*,n>=2)                                     ③

显然:

                                                            F(0) = F(1) = 1

所以:

                                                         F(n) = \left\{\begin{matrix} 2^{n-1} & n\in N^{*} \\ 1 & n=0 \end{matrix}\right.

不建议在③步就用递归或从前向后的解法,那属于数列没学好的做法,明明有更简单的通项公式为什么不用呢,如果这是高中求数列的题,到③就结束,保证你被数学老师一顿乱k

import math


f = lambda n: 2**((n or 1)-1)
# f = lambda n: 2**(n-1) if n else 1
# f = lambda n: math.ceil(2**(n-1))  # 一样快

n阶台阶,每次可以跳1、2、... 、k阶

n阶台阶,每次可以跳m0, m1, m2, ..., mk阶

用零钱凑成n元,零钱有足够量的1、2、5、10、20、50、100元面值

猜你喜欢

转载自blog.csdn.net/lnotime/article/details/82692848
今日推荐