Skip to content
本页目录

动态规划

解决动态规划题的思路分为两步:先想好了思路,再动手实现

  1. 思路 -> 确定状态转移方程(相同问题在不同规模下的关系)
  2. 实现

什么是确定状态转移方程?

确定状态转移方程其实就是一个关系相同问题在不同规模下的关系,看起来很抽象对吧,简单来讲,就是通过总结的规律,推导出数学公式。

比如动态规划的入门题目,求斐波那契数列第n位的值,我们知道,斐波那契前七位如下:

shell
1 1 2 3 5 8 13

我们使者来找一下规律:

  • 第一位为1, 第二位为1, 第三位为 2, 第四位为 3
  • 每一位 = 前两位数之和

假设我们有个函数名叫 dp(n)

  • dp(n) 中的 n 就表示相同问题在不同规模下的关系 这就话中的 不同规模
  • n 越大, 问题的规模就越大
  • dp(4)表示求斐波那契数第4位的值, dp(5)表示第5位, dp(6)表示第6位...

所以我们推导出下面规律:

js
dp(6) = dp(5) + dp(4)
dp(n) = dp(n - 1) + dp(n - 2)
  • dp(6) dp(5) dp(4) 是三个不同规模的问题,他们解决的是相同的问题,都是求斐波那契数列某一位的值, 但规模不一样。
  • 所以 dp(6) dp(5) dp(4) 之间的关系我们称之为状态转移方程,也就是 dp(n) = dp(n - 1) + dp(n - 2)

然后,我们在确定状态转移方程的时候,往往需要考虑一些特殊解

js
dp(6) = dp(5) + dp(4)
dp(n) = dp(n - 1) + dp(n - 2)

// 考虑特殊解
dp(1) = 1
dp(2) = 1
斐波那契数列的动态转移方程

当 n > 2

js
dp(n) = dp(n - 1) + dp(n - 2)

当 n <= 2

js
dp(n) = 1

所以我们很容易能实现代码:

js
function dp(n) {
  // if (n === 1 || n === 2) return 1
  if (n <= 2) return 1
  return dp(n - 1) + dp(n - 2)
}

寻找状态转移方程的一般性步骤

  1. 找到相同问题(重叠子问题), 「相同问题」必须能适配不同的规模
  2. 找到重叠子问题 之间的关系
  3. 找到重叠子问题之间的 特殊解