动态规划刷题总结

文章目录

      • 什么样的问题适合动态规划
      • 动态规划的步骤
        • 状态定义
        • 状态转移
        • 状态边界处理
        • 编写代码
        • 空间优化

什么样的问题适合动态规划

数据结构与算法:41 |动态规划理论:最优子结构、无后效性和重复子问题_zj-CSDN博客

一个模型:多阶段决策最优解模型,重点在于多阶段,每个阶段都对应着不同的状态

三个特征:最优子结构,无后效性,重复子问题。主要抓住最优子结构这一特征,理解为后面的阶段状态可以由前面的阶段状态推导而来。

动态规划的步骤

状态定义

首先应该思考怎么样把原问题划分为多个阶段,然后判断我们是需要一维的状态还是二维的状态(这一步通常比较容易),以及搞清楚每个状态的实际意义是什么。

比如leetcode 第 64 题:最小路径和(C++)_zj-CSDN博客_leetcode c++最小路径调试模板,这个问题:数组中的每个位置都可以对应一个阶段,所以我们可以定义二维的dp数组dp[i][j],i 和 j就表示每个阶段的坐标,数组的元素值 dp[i][j]就是状态值, 代表从左上角走到 (i, j)这个位置的路径和。

状态转移

两种思考方式,向前或者向后(本质上没区别),不过为了计算方便,更多的时候我们会选择向前思考:

  • 向后思考:假设当前阶段处于 (i, j) 这个位置,我们下一个阶段有可能转移到哪个位置。
    还是上面的例子,由于只能向下/向右移动,所以明显下一阶段可能会走到 (i+1, j) 或者 (i, j+1)的位置。所以这两个位置的状态值就可以由 (i, j)的状态值 dp[i][j] + grid[i+1][j]/grid[i][j+1]计算而来,然后我们就可以考虑更新 (i+1, j) 和 (i, j+1)这两个阶段的状态值了,至于怎么更新,就看题目是要求求最小值还是最大值或者其他的,根据需要选取即可。
  • 向前思考:假设当前阶段处于 (i, j) 这个位置,那就思考我们是从哪个位置转移到(i, j) 这个位置的呢?还是上面的例子,由于只能向下/向右移动,所以我们只能从 (i-1, j) 或者 (i, j-1)的位置转移而来,那么就需要根据题意(最大,最小…)对这两种转移进行选择。本题要求是求最小的路径和,那就看哪一个转移过来的路径和最小,就选哪一个:
    f [ i ] [ j ] = m i n ( f [ i ] [ j − 1 ] , f [ i − 1 ] [ j ] ) + g r i d [ i ] [ j ] f[i][j] = min(f[i][j-1], f[i-1][j]) + grid[i][j] f[i][j]=min(f[i][j1],f[i1][j])+grid[i][j]

状态边界处理

状态转移总会有一个开始/结束或者边界的地方,这些地方的状态和其他地方稍有差别,我们需要特殊处理。常见的有二维dp数组的第一行、第一列,一维dp数组的第一个元素,我们需要特殊赋值。

不过这一部分通常比较简单,很多时候都是赋1或者赋0,进行简单的推导即可。

编写代码

有了状态转移方程之后,编写代码就相对容易了。不过还是需要注意边界的处理,是很容易忽略的地方。

空间优化

对于很多dp问题来说,比如上面的那个例子,其实并不需要完整的二维dp数组,很多时候都可以使用滚动数组或者一位数组进行替代,不过很多时候空间优化后的代码可读性会降低,可以自行考虑。

你可能感兴趣的:(数据结构与算法,leetcode,动态规划)