动态规划学习+理解

在leetcode上刷题刷到过很多有关于动态规划的题目,然后就去网上找各种大佬的分析,其实我这个专业虽然是计算机学院的,但是并没有上过算法课,只学过数据结构里面的一些查找排序算法,个人觉得这是学校安排的重大失误,毕竟计算机学院的数据结构,算法,计算机组成,计算机操作系统,计算机网络都是必学的内容。

我讲下动态规划学习的过程把,然后我会把一些典型的题目讲一下

动态规划需要实现的三个目标:

1.建立状态转移方程

感觉这一步是最难的,就像高中数学的压轴找规律题目,找出来就简单了,但是难就难在这个状态转移方程太难找,但是我们只需记住当已经知道f(1)~f(n-1)时,利用它们算出f(n)的值。比如一只狗狗4条腿,n只就是4n条腿,所以状态转移方程:f(n)=f(n-1)+4。看到这里大家是不是想到的递归呢,但是这里的动态规划就是为了解决递归的高复杂度的,因为f(1)~f(n-1)已经知道了啊,如果用递归的话假如n=5,那么f(5)要算一遍f(3),f(4)又要算一遍f(3),这就造成了浪费,所以记住,能用迭代就不用递归

2.复用以往结果

比如在上面数狗腿的例子中,求f(100),在不能用显式方程(f(n)=4n)的情况下,用状态转移方程来解也就是用f(n)=f(n-1)+4,如果缓存以往的结果则当我们算f(100)的时候只需要用以前算过的f(99)+4就行了,否则则需要进行100次加法运算

3.按顺序从小到大算

在这里也就是我们要从 f(1),f(2),f(3)... 到​f(n) 依次顺序计算。这一点在“数腿”的例子来看,似乎显而易见,因为状态方程基本限制了你只能从小到大一步步递推出最终的结果(假设我们仍然不能用显式方程)。然而当问题复杂起来的时候,你有可能乱了套

经典题:斐波那契数列

一种方法很显然大家都想到递归:

def fib(n):
    if n < 2:
        return n
    else:
        return fib(n-1)+fib(n-2)


#test

xx = fib(100)

这个代码是极其低效的,为什么极其低效呢,就比如算f(5),如下图,绝大多数的递归都可以转换成迭代的方式,只是递归的实现代码可能非常简单

 

 

 那用动态规划呢?

def fib(n):
    result = list(range(n+1))
    for x in range(n+1):         #从小到大算,目标3
        if x<2:
            result[x] = x
        else :
            result[x] = result[x-1]+result[x-2] #缓存结果,目标2,转移方程,目标1
    return result[n]
#test
xx = fib(100)

 相比之下:

 问题二:青蛙跳台阶

一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶。求该青蛙跳上一个 n 级的台阶总共有多少种跳法。

怎么理解呢?首先f(n)表示跳上n级台阶的f(n)种跳法,青蛙最后一步有两种情况,跳1级或者跳2级,剩下n-1台阶还有f(n-1)跳法,剩下n-2台阶还有f(n-2)种跳法,所以f(n)=f(n-1)+f(n-2),但是这个问题f(0)=1,f(1)=1,f(2)=2,本质还是斐波那契数列

所以代码如下:

def qw(n):
    a=1
    b=1
    for _ in range(n):
        a,b=b,a+b
    return a

    
#test
xx = qw(100)

问题3:不同路径

 

 用f(i,j)表示到该格子的路径数,可以得出,每个格子只能从它左边或者右边的格子到达,所以转换方程:f(i,j)=f(i-1,j)+j(i,j-1)

这样我们参照前面的三个目标代码就知道怎么写了:

def path_num(a,b):  #a,b代表横纵坐标
    # 每个元素赋初值1,路径数嘛
    result = [[1 for _ in range(b)] for _ in range(a)]#a行b列二维数组的创建,还有另外一种方法
    for i in range(1,a):
        for j in range(1,b):
            result[i][j] = result[i-1][j]+result[i][j-1]
    return result[-1][-1]

#test
xx = path_num(3,5)
    
    

记住动态规划的三个目标,从这三个目标下手,会让动态规划显得更加简单

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值