以下内容参考转载来源(本人只是为了自己学习方便做了归纳整理):
http://baijiahao.baidu.com/s?id=1570689459307346&wfr=spider&for=pc
动态规划包含了三个重要的概念:最优子结构、边界、状态转移公式。
- 题目:有一座高度是10级台阶的楼梯,从下往上走,每跨一步只能向上1级或者2级台阶。要求用程序来求出一共有多少种走法。
求解思路1:
先考虑只差最后一步就走到第十级台阶,有几种走法?
两种,从9级到十级,和从8级到10级。那么到10级的走法就是到8级的走法与9级的走法之和。
可以归纳出以下公式:
F(1)=1;
F(2)=2;
F(n)=F(n-1)+F(n-2)(n>=3)
上式中,F(1)和F(2)是边界,F(n)=F(n-1)+F(n-2)(n>=3)是状态转移方程,之前分析的F(8)和F(9)是F(10)的最优子结构。
接下来看以下几种求解方法:
- 递归求解
int getClimbingWays(int n){
if (n<1){
return 0;
}
if (n==1){
return 1;
}
if (n==2){
return 2;
}
return getClimbingWays(n-1) + getClimbingWays(n-2);
}
此时计算过程如下图,二叉树的高度N-1,节点个数接近2的N-1次方,即改方法时间复杂度接近O(2^n)
通过观察二叉树会发现很多参数被重复计算了,因此可以创建一个哈希表:
2. 哈希表
int getClimbingWays(int n, HashMap<Integet, Interger>map){
if (n<1){
return 0;
}
if (n==1){
return 1;
}
if (n==2){
return 2;
}
if(map.contains(n)){return map.get(n)};
else{
int value = getClimbingWays(n-1) + getClimbingWays(n-2);
map.put(n, value);
return value;
}
}
F(1)到F(N)一共又N个不同的输入,哈希表存了N-2个结果,此时时间复杂度和空间复杂度都是O(N)。
在上述方法中,计算F(N)都是自顶向下做递归,而我们已知了边界值,此时可以考虑自底向上迭代,分析此时的迭代过程,回发现每一个状态都只依赖于它的前两个状态。
3. 动态规划
int getClimbingWays(int n){
if (n<1){
return 0;
}
if (n==1){
return 1;
}
if (n==2){
return 2;
}
int a=1;
int b=2;
int temp=0;
for (int i=3;i<=n;i++){
temp=a+b;
a=b;
b=temp;
}
return temp;
}
此时时间复杂度O(N),只有两三个变量,空间复杂度O(1).
不过这个问题是入门级的动态规划,只有一个变化问题,有许多实际问题比这难许多。