动态规划面试宝典(极客时间)学习笔记

动态规划面试宝典(极客时间)学习笔记

局部最优解

​ 贪心算法就是一种经典的求解“局部最优解”的算法

整体最优解

​ 动态规划

重叠子问题与备忘录

由斐波那契数列引出的重叠子问题

int febnaci (int n){
    if(n=0){
        return 0;
    }
    if(n=1){
        return 1;
    }
    if(n>1){
        return febnaci(n-1)+febnaci(n-2);
    }
    return 0;//如果输入n有误,返回默认值
}
//由于涉及到递归,效率很低,重复计算了很多子问题,它是自顶向下的

​ 所谓重叠子问题,就是在大问题求解过程中会重复求解小问题

通过备忘录来解决重叠子问题

​ 从求解顺序上来解决这个问题。在处理每个大问题之前,必须要求解哪些小问题,将小问题的解存放于备忘录中。从而就可以逐步根据小问题得到大问题的解。

动态规划问题特征:

  • 重叠子问题:在穷举过程中(通过递归),存在重复计算的现象;

  • 无后效性:子问题之间的依赖是单向性的,某阶段状态一旦确定,就不受后续决策影响;

  • 最优子结构:子问题之间必须相互独立,或者后续的计算可以通过前面的状态推导出来。

    动态规划首要解决的是“最优解”问题(最大值和最小值),即从很多解决问题的方案中找到最优的那一个。而求最优解的问题核心是穷举,把一个大问题分解为多个子问题,然后递归的找到每个子问题的最优解。最后,通过算法将每个子问题的最优解进行组合,得出原问题的答案。

状态方程

  • 初始化状态:由于动态规划是根据已经计算好的子问题推广到更大问题上去的,因此需要一个“原点”作为“计算”的开端
  • 状态参数:找出子问题与原问题之间会发生变化的变量
  • 状态存储:dp[i]=Math.min(dp[i-1],num[i]+dp[i-1])
  • 决策与状态转移:改变状态,让状态不断逼近初始化状态的行为

经典的动态规划问题

  • 求最优解(最大值和最小值):从一系列方案中寻找最优解决方案
  • 求方案总数:计算满足要求的解决方案的数量
  • 求可行性(True或False):确定 提出的问题是否存在可行性方案

代表性问题如下

1.背包问题

  • 0-1 背包:每个物品最多要么选择1个,要么选择0个。因此称之为0-1背包。所有物品的数量k[i]都为1。
  • 完全背包:每个物品的数量都是无限的。
  • 多重背包:每个物品都有固定的数量,指定了k[i]。

无论0-1背包还是完全背包,其实都是多重背包的特例。

解题框架:

首先,确定初始化状态,当没有物品时,重量为0,重量为0时,物品数量也为0。

接着,确定状态参数,也就是会影响我们进行决策的变量:

  • 背包内物品数量N在增加,它是一个变量
  • 背包内还能装下的物品重量在减少,也是一个变量。

因此,当前背包内的物品数量N和背包还能装下的重量W就是这个动态规划问题的状态参数

接着,再看如何决策。由于每种物品的数量为k[i],因此可以将同一种物品多次放入背包。**核心在于:**针对一种物品,需要考察拿不同数量的情况下的最优解,也就是针对当前物品,应放入多少件当前物品,价值最大。

最后,动态规划需要一个备忘录来加速算法。由于有两个状态参数,考虑使用二维数组来存储子问题的答案。将其命名为dp[tn] [rw],它的含义是:背包容量还剩 rw时,放入前tn种物品时的最大价值。

通用的背包状态转移方程
D P ( t n , r w ) = D P ( t n − 1 , r w ) , r w < w [ t n ] DP(tn,rw)=DP(tn-1,rw) ,rw<w[tn] DP(tn,rw)=DP(tn1,rw),rw<w[tn]

D P ( t n , r w ) = m a x [ D P ( t n − 1 , r w − k ∗ w [ t n ] ) + k ∗ v [ t n ] ] , 0 < = k < = m i n ( k [ t n ] , r w / w [ t n ] ) DP(tn,rw)=max[DP(tn-1,rw-k*w[tn])+k*v[tn]],0<=k<=min(k[tn],rw/w[tn]) DP(tn,rw)=max[DP(tn1,rwkw[tn])+kv[tn]],0<=k<=min(k[tn],rw/w[tn])

2.路径问题

路径问题是求解总方案数量的经典代表问题。

机器人移动路径问题,直接给出状态转移方程:

D P ( i , j ) = ( D P [ i − 1 ] [ j ] + D P [ i ] [ j − 1 ] ) i f i ! = 0 o r j ! = 0 DP(i,j)=(DP[i-1][j]+DP[i][j-1]) if i!=0 or j!=0 DP(i,j)=(DP[i1][j]+DP[i][j1])ifi!=0orj!=0

D P ( i , j ) = 1 , i = 0 a n d j = 0 DP(i,j)=1, i=0 and j=0 DP(i,j)=1,i=0andj=0

3.跳跃游戏

可行性的代表问题:跳跃游戏

**题目:**给出一个非负整数数组 A,你最初定位在数组的第一个位置。数组中的每个元素代表你在那个位置可以跳跃的最大长度。判断你是否能到达数组的最后一个位置。

示例1:

输入:A = [2, 3, 1, 1, 6]
输出: True
解释: 我们可以先跳 1 步,从位置 0 到达位置 1, 然后再从位置 13 步到达最后一个位置。

首先确定初始化状态 ,0这个位置可以初始化为True

接着确定状态参数,由于只有一个状态参数,因此可以使用一位数组DP[i]来表示能否从出发点到达位置i

最后确定状态转移与决策,想要知道能否到达位置i,就需要逐个看前面的位置,判定能否从位置i-1,i-2,i-3…跳到位置i上,然后再看i-1这个位置能否到达。

给出状态转移方程的定义:
D P [ i ] = T r u e , i = 0 DP[i]=True , i=0 DP[i]=True,i=0

D P [ i ] = ( D P [ j ] = t r u e ) a n d ( m a x ( A [ j ] + j ) > = i ) , i ! = 0 a n d j < i DP[i]= (DP[j]=true) and (max(A[j]+j)>=i) ,i!=0 and j<i DP[i]=(DP[j]=true)and(max(A[j]+j)>=i),i!=0andj<i
4.其他问题

除了上面提到的几类代表性问题,还有两类问题需要关注:子数组问题和子序列问题。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值