前言:本文一些地方参考了小灰写的漫画《什么是动态规划》,里面写的很形象生动容易理解。自我感觉能把里面的都看懂两个问题实现一遍,分析时间空间复杂度,动态规划就算是入门了。但是就金矿的分析那里并不完全正确,代码是有问题的,尤其是用Java写的一定不要参照它里面的代码,里面的数组使用有很大问题。
一. 动态规划是什么
1. 基本概念
- 以斐波那契数列为例:0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55…
- 动态规划中包含三个重要的概念:边界、最优子结构、状态转移公式
+ F(0)=0、F(1)=1 就是求解斐波那契数列的边界,这个概念有点类似于递归的初始值
+ F(2)=F(0)+F(1) 那么F(2)的最优子结构就是F(0)+F(1)
+ F(n)=F(n-1)+F(n-2) (n>=3) 这个是它的状态转移公式,状态转移公式我们可以通过多找几个最优子结构总结规律就可以了
2. 核心思想
- 动态规划算法的核心:通过将某个子问题的计算结果保存到内存表中,为之后的问题提供服务,避免对子问题的重复求解,以此来提高执行效率。也就是通过牺牲空间,换来了时间效率,即time-memory trade-off
-两种实现方法:一种是top-down,一种是bottom-up
二、例题
1. 爬楼梯
题目:有一座高度是10级台阶的楼梯,从下往上走,每跨一步只能向上1级或者2级台阶,求出一共有多少种走法。
- 分析:
+ 假如说只差最后一步就走到第10级台阶会出现两种情况,第一种是从第9级走1级上到第10级,第2种是从第8级走2级上到第10级。
+ 那么引申出一个新的问题:如果我们已知0到9级台阶的走法有X种,0到8级台阶的走法有Y种,那么0到10级台阶的走法有多少种?
+ 10级台阶的所有走法可以根据最后一步的不同而分成两部分:第一部分的最后一步是从9级到10级,这部分的走法数量和9级台阶的走法数量是相等的,也就是X;第二部分的最后一步是从8级到10级,这部分的走法数量是和8级台阶的走法数量是相等的,也就是Y。这两部分相加,总的走法数量是X+Y。
+ 进而可以得出F(10)=F(9)+F(8) , F(9)=F(8)+F(7) …
- 公式:
+ 边界:F(0)=0; F(1)=1; F(2)=2;
+ 状态转移公式:F(n)=F(n-1)+F(n-2) (n>=3);
- 1.1 递归求解(top-down)
public class Climb {
public static int getClimbWays(int steps){
if(steps<=2)
return steps<1?0:steps;
else