动态规划:分阶段求解决策问题的数学思想。可用于编程,管理,经济,生物等多方面。
在动态规划中有三个重要的概念:
1、最优子结构
2、边界
3、状态转移公式
举例:
有10个台阶,每次可以上1个台阶或2个台阶,总共有多少种走法可以完成?
1、暴力破解,通过枚举的方式,时间复杂度较高。
2、动态规划。
最后一步到第10级台阶的走法有两种,要不是从第9级一步到10级,或者是从第8级两步到10级。所以:
f(10)=f(9)+f(8)
这其中
f(9)和f(8)就是f(10)的最优子结构
f(1)和f(2)就是问题的边界,无需继续简化
f(n)=f(n-1)+f(n-2)就是阶段与阶段之间的状态转移方成,它是核心,决定了问题每个阶段与下个阶段的关系。
第一步问题建模完成。
第二步求解
方法1:递归。
递归代码逻辑比较简单,但是时间复杂度较高。会出现大量重复计算,针对f(n-2)等都有重复计算。
int getClimbWays(int n){
if(n<1){
return 0;
}
if(n==1){
return 1;
}
if(n==2){
return 1;
}
return getClimbWays(n-1)+getClimbWays(n-2)
}
方法2:递归+备忘录算法。
备忘录算法,将之前计算过的参数的结果记录下来,利用哈希表。
int getClimbWays(int n){
if(n<1){
return 0;
}
if(n==1){
return 1;
}
if(n==2){
return 1;
}
if(map.get(n)){
return map.get(n);
} else {
int value = getClimbWays(n-1)+getClimbWays(n-2);
map.put(value,n);
return value;
}
}
方法3:进一步降低空间复杂度,采用从底向上递归的方式,这样就值需要保留前两个迭代的状态变量。
int getClimbWays(int n){
if(n < 1){
return -1;
}
if(n==1){
return 1;
}
if(n==2){
return 1;
}
int a=1;
int b=1;
int temp=0;
for(int i=3;i<=n;i++){
temp = a + b;
a = b;
b = temp;
}
return temp;
}