面向leetcode学习动态规划

什么是动态规划

用上一部得到的结果去做下一步. 也就是 "记录结果再利用".

将原问题拆解成若干子问题,同时保存子问题的答案,使得每个子问题只求解一次,最终获得原问题的答案。

在处理更大规模的问题的时候,直接使用了更小规模问题的结果。

道理都懂, 但做题总感觉差点什么

接下来我会取3个leetcode的动态规划题来举例, 读者最好先试着做做哦.

它们分别是

(go代码算法可参看我的github)

不知道思路的话, 试一试以下三个步骤.

先弄清楚解的依赖关系

比如221题, 某个点的解由上,左,左上3个点决定, 764题, 点的解由上,下,左,右4个点决定.

如何找依赖关系呢? 我的方法是将例子写在本子上, 人脑去验算, 尝试找到每个解之间的关系, 当然多做两个题之后也就孰能生巧了.

思考过程也是有套路的:

  1. 弄清楚在每一步求解过程中有那些变量控制解
  • 如211题, 对于每一个i行j列都有一个解去对应, 变量就是i行j列, 764题同样.
  • 再说322题, 题目中硬币是无限的, 在求每一步的解时, 硬币没有发生任何变化, 那么影响解的变量只有amount.
  1. 变量依次改变(一般是从小变大), 去演算解, 如在求斐波那契数列第10项时, 先去演算第一项, 再去演算第二项, 你就会发现两项之间的关系.
  • 如211题, p[i,j]p[i-1,j-1]之间的关系就是: 至少p[i-1,j-1]是正方形, p[i,j]才能是正方形,
    再思考p[i,j]p[i,j-1]的关系也是同理, 现在你就得到了解之间的关系.
  • 如322题, p[amount]p[amount-1]的关系就是: 如果我取出了面值为1的硬币, 那么所需硬币的最小数量p[amount]=1(取走了1个硬币)+p[amount-1(硬币面额为1)],
    再推理一下, 这里的1其实是硬币的面额, 替换下变量既得到p[amount] = 1 + p[amount - coins[i]]

最后将思考结果用公式写出来, 方便写代码.

公式可以看做黑盒的方法, 可不用管题目参数, 直接写变量和解之间的公式.

  • 211题
p[i,j] = min(1 + p[i-1,j], 1 +  p[i,j-1], 1 +  p[i-1,j-1])
  • 764题
p[i,j] = min(1 + p[i-1,j], 1 +  p[i+1,j], 1 +  p[i,j-1], 1 +  p[i,j+1])
  • 322题
p[amount] = min(1 + p[amount - coins[i]], i=0~len(coins)) 

ps: 如果不能理解, 就在参考看看每个题的注释: 211, 764, 322.

想好如何保存解

弄清楚解的依赖关系之后, 还需要弄清楚如何将上一步的解保存下来提供给下一步利用.

注意这里的保存是一个广泛的意思, 不一定是存在一个全局的数据结构里(如数组), 也可以存在局部变量中.

特别是做大量数据的题时候, 尽量用局部变量去存储这一步的解, 实在没办法再想到用全局去存.

举个例子: 求斐波那契数列的第10项

这个题有两种解法,

  1. 声明一个数组s [10]int, 循环10次, s[i] = s[i-1] + s[i-2]
  2. 声明两个变量 a,b, 循环10次, c=a+b; a=c

可以看到解法1所需要的空间比2大得多, 当题目没要求需要得到每一步的解的时候, 最好使用解法2.

当然两种解法的差别还不只是空间.

如764题, 每个点的解由上,下,左,右4个点决定, 那么如果要将解存到全局的话, 需要声明一个复杂的数据结构以保存4个解, 最后写出来又复杂, 所需要空间也大.

所以更好的方式是在遍历过程中, 直接用局部变量保存上一步的解, 具体做法看代码啦.

循环(遍历)

最后 循环也很关键, 它直接影响了结果的正确性 和 保存解的复杂度.

对于每一个题, 解的公式不一样, 所以遍历的先后顺序也不一样.

但其实只需要记得保持一个原则: 按照依赖关系去遍历, 保证上一步解在本次操作之前已经正确的解出来了.

所以要将解的依赖关系理解透彻.

在写代码的过程中, 记得反复推敲此行代码所依赖的上一步解是否已经解过了

(笔者也才开始做leetcode, 没啥心得, 不能落笔于此, 惭愧. 先题海战术吧~)

具体做法就看我的github吧. 211题, 764题, 322题

参考

ps: 学习的第一步一定是仿照(抄袭), 写不出代码就先把别人的代码抄懂, 这很正常. 不过之后记得多总结, 思考别人是怎么想到答案的, 最后尝试用学到的几种不同的思维方式去解题.

ps: 做题真费脑子, 希望自己能坚持, 等到变强了, 做题也就轻松了.

猜你喜欢

转载自blog.csdn.net/weixin_34324081/article/details/87137485