动态规划入门----斐波那契数列(搬

视频地址:https://www.youtube.com/watch?reload=9&v=vYquumk4nWw

可以通过三个方式写出斐波那契数列:递归,备忘录,自底向上

1.递归

def fib(n):
    if n == 1 or n == 2:
        result = 1
    else:
        result = fib(n - 1) + fib(n - 2)
    
    return result

使用递归的会产生大量的重复计算,比如要计算fib(5),就要多次计算fib(3),fib(2)等之前计算过的值,浪费很多的空间和时间,当n值变得很大的时候,计算时间成指数增长,时间复杂度为O(2^n)。

那么怎么去优化这个程序呢?我们可以将其之前计算过的fib值使用一个列表或者其他容器存储起来,当之后计算需要使用的时候就直接使用,不再去重复计算。这里就引入了备忘录的解决方法。

# 函数传入两个参数,一个n和一个memo用来存储计算过的值
def fib(n, memo):
    # 若第n个fib的值已经在memo中,就直接返回
    if memo[n] != None:
        return memo[n]
    if n == 1 or n == 2:
        result = 1
    else:
        result = fib(n - 1) + fib(n - 2)
    # 每次计算的结果都存入memo
    memo[n] = result
    
    return result
# 伪代码,源码在下面

此时时间复杂度为O(2n+1) ---> O(n)远小于O(2^n)。还可以在备忘录的基础上继续优化,不使用递归来做,函数依然指传入第n个fib求解,函数中定义一个n+1长度的数组(列表),从1开始存储值,第一位是1,第二位也是1,这两项就是动态规划中的初始状态的值(边界状态),从第三项开始一直到n进行fib的计算,bottom_up[i] = bottom_up[i-1] + bottom_up[i - 2]就是动态规划要使用到的状态转移方程,最终返回列表顶部的数,自底向上方法也就是动态规划的方法求解的fib,时间复杂度也是O(n)。

   动规解题的一般思路

    1. 将原问题分解为子问题

  •     把原问题分解为若干个子问题,子问题和原问题形式相同或类似,只不过规模变小了。子问题都解决,原问题即解决(数字三角形例)。
  •     子问题的解一旦求出就会被保存,所以每个子问题只需求 解一次。

    2.确定状态

  •     在用动态规划解题时,我们往往将和子问题相关的各个变量的一组取值,称之为一个“状 态”。一个“状态”对应于一个或多个子问题, 所谓某个“状态”下的“值”,就是这个“状 态”所对应的子问题的解。
  •     所有“状态”的集合,构成问题的“状态空间”。“状态空间”的大小,与用动态规划解决问题的时间复杂度直接相关。 在数字三角形的例子里,一共有N×(N+1)/2个数字,所以这个问题的状态空间里一共就有N×(N+1)/2个状态。

    整个问题的时间复杂度是状态数目乘以计算每个状态所需时间。在数字三角形里每个“状态”只需要经过一次,且在每个状态上作计算所花的时间都是和N无关的常数。

    3.确定一些初始状态(边界状态)的值

    以“数字三角形”为例,初始状态就是底边数字,值就是底边数字值。

    4. 确定状态转移方程

     定义出什么是“状态”,以及在该“状态”下的“值”后,就要找出不同的状态之间如何迁移――即如何从一个或多个“值”已知的 “状态”,求出另一个“状态”的“值”(递推型)。状态的迁移可以用递推公式表示,此递推公式也可被称作“状态转移方程”。

--------------------- 本文来自 ChrisYoung1314 的CSDN 博客 ,全文地址请点击:https://blog.csdn.net/baidu_28312631/article/details/47418773?utm_source=copy

图片上的都是伪代码,源码放在下面了。

def fib_2(n, memo):
    if memo[n] is not None:
        return meno[n]
    if n == 1 or n == 2:
        result = 1
    else:
        result = fib_2(n - 1, memo) + fib_2(n - 2, memo)
    memo[n] = result
    return result

def fib_memo(n):
    memo = [None] * (n + 1)
    return fib_2(n, memo)
def fib_bottom_up(n):
    if n == 1 or n == 2:
        return 1
    bottom_up = [None] * (n + 1)
    bottom_up[1] = 1
    bottom_up[2] = 1

    for i in range(3, n + 1):
        bottom_up[i] = bottom_up[i - 1] + bottom_up[i - 2]
    
    return bottom_up[n]

 

  • 8
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Python 是一种易于学习且功能强大的编程语言,适合青少年学习编程。下面是一个简单的 Python 编程教程,可以帮助青少年入门。 1. 安装 Python 首先,需要安装 Python 解释器。可以从 Python 官网下载并安装,也可以使用 Anaconda 发行版,它包括了 Python 解释器和很多常用的库和工具。 2. 编写第一个 Python 程序 打开 Python 解释器或者文本编辑器,在代码编辑区域输入以下代码: ``` print("Hello, world!") ``` 这是一个经典的入门示例,它会输出 "Hello, world!" 到屏幕上。保存文件并运行即可看到结果。 3. 基本语法 Python 使用缩进来表示代码块,而不是花括号。例如,下面是一个 if 语句的示例: ``` if x > 0: print("x is positive") else: print("x is zero or negative") ``` 这个示例中,如果变量 x 的值大于 0,就会输出 "x is positive",否则输出 "x is zero or negative"。 4. 数据类型 Python 支持多种数据类型,包括整数、浮点数、字符串、列表、元组、字典等。例如,下面是一个列表的示例: ``` fruits = ["apple", "banana", "cherry"] print(fruits[0]) # 输出 "apple" ``` 这个示例中,定义了一个包含三个元素的列表 fruits,并且输出了列表中的第一个元素 "apple"。 5. 函数 Python 支持函数的定义和调用。例如,下面是一个计算斐波数列的函数: ``` def fibonacci(n): if n == 0: return 0 elif n == 1: return 1 else: return fibonacci(n-1) + fibonacci(n-2) print(fibonacci(10)) # 输出 55 ``` 这个示例中,定义了一个名为 fibonacci 的函数,它接受一个参数 n,并且根据斐波数列的递推公式计算出第 n 个数的值,并将结果返回。然后,在主程序中调用 fibonacci 函数并输出结果。 这些是 Python 编程的基础知识,希望可以帮助青少年入门编程。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值