动态规划
什么是动态规划?
动态规划是运筹学的一个分支,是求解决策过程最优化的数学方法。它将问题拆分成小问题,并解决小问题作为起点,从而最终解决问题。
接下来我们从简单的例子看起,感受一下动态规划算法的魅力。
问题一:爬梯子问题
假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
注意:给定 n 是一个正整数。
示例 1:
输入: 2
输出: 2
解释: 有两种方法可以爬到楼顶。
a、1 阶 + 1 阶
b、2 阶
示例 2:
输入: 3
输出: 3
解释: 有三种方法可以爬到楼顶。
a、1 阶 + 1 阶 + 1 阶
b、1 阶 + 2 阶
c、2 阶 + 1 阶
走1阶台阶只有一种走法,但是走2阶台阶有两种走法(如示例1),如果n是双数,我们可以凑成m个2级台阶,每个m都有两种走法,如果n是单数,那么我们可以凑成m个2级台阶加上一个1级台阶,这样就似乎于一个排列组合题目了,但是开销貌似比较大。
如何将整个问题拆分成一个一个的小问题呢?
这个时候使用动态规划就很有用,因为这个问题其实是由一个很简单的小问题组成的。
观察这种小问题,简单地我们可以采用首位或者中间态进行一次分析,比如我们从最终态进行分析:
走N阶台阶,最后一步必定是1步或者2步到达。
那么N阶台阶的走法不就相当于最后走一步和最后走两步的走法的总和吗?换一种方式来说,我们取一个中间态:如果总共有3级台阶,3级台阶的走法只会存在两种大的可能:走了1阶台阶+走两步、走了两级台阶+走一步,即3级台阶的所有走法就是走了1阶台阶的走法加上走了2阶台阶的走法,而1阶台阶的走法只有一种,2阶台阶的走法有2种,所有3阶台阶的走法有3种,我们使用一种更通用的方式进行表达的话就是所谓的状态转换方程:
ways[n] = ways[n-1] + ways[n-2]
有了这个公式,我们就可以使用迭代来完成整个过程,寻求到最终的ways[n]的值了,迭代的开始即我们已知的确定条件:一阶台阶只有一种走法:ways[1]=1、两阶台阶有两种走法:ways[2]=2,代码如下:
function climbStairs(n) {
if (n === 1 || n === 2) {
return n;
}
var ways = [];
ways[0] = 1;
ways[1] = 2;
for(var i=2; i<n; i++){
ways[i]=ways[i-1] + ways[i-2];
}
return ways[n-1];
}
梳理一下基本流程:
1、从一个现实方案中找到状态转换的特有规律
2、从特有规律中提取出状态转换方程
3、找到状态转换方程的迭代初始值(确定值)
4、解决问题