You are climbing a stair case. It takes n steps to reach to the top.
Each time you can either climb 1 or 2 steps. In how many distinct ways can you climb to the top?
Note: Given n will be a positive integer.
Example 1:
Input: 2
Output: 2
Explanation: There are two ways to climb to the top. 1. 1 step + 1 step 2. 2 steps
Example 2:
Input: 3
Output: 3
Explanation: There are three ways to climb to the top. 1. 1 step + 1 step + 1 step 2. 1 step + 2 steps 3. 2 steps + 1 step
爬楼梯,一次可以爬一级或者两级楼梯。问爬到n级楼梯有多少中方法。
分析:爬到n,可以是从n-1级楼梯一次爬上来,也可以是从n-2级一次走两步上来(不能从n-2走一步再走一步,因为走一步就会去到n-1级,重复)。所以有公式f(n)=f(n-1)+f(n-2)。
递归是可以解决的,但是递归会出现超时的情况。
所以使用动态规划。动态规划也没有什么特别之处,就是把一个大问题分解成许多个子问题,子问题解决了,大问题也就解决了。比如这里的f(n),可以先求f(3),再根据状态方程求后一项,。。。,。这就是动态规划。
递归都可以转成动态规划。
动规解题的一般思路
1. 将原问题分解为子问题
- 把原问题分解为若干个子问题,子问题和原问题形式相同或类似,只不过规模变小了。子问题都解决,原问题即解决。
- 子问题的解一旦求出就会被保存,所以每个子问题只需求 解一次。
2.确定状态
- 在用动态规划解题时,我们往往将和子问题相关的各个变量的一组取值,称之为一个“状 态”。一个“状态”对应于一个或多个子问题, 所谓某个“状态”下的“值”,就是这个“状 态”所对应的子问题的解。
- 所有“状态”的集合,构成问题的“状态空间”。“状态空间”的大小,与用动态规划解决问题的时间复杂度直接相关。
3.确定一些初始状态(边界状态)的值
以“爬楼梯”为例,初始状态就是f(1),f(2),值就是数字值。
4. 确定状态转移方程
定义出什么是“状态”,以及在该“状态”下的“值”后,就要找出不同的状态之间如何迁移――即如何从一个或多个“值”已知的 “状态”,求出另一个“状态”的“值”(递推型)。状态的迁移可以用递推公式表示,此递推公式也可被称作“状态转移方程”。
从递推公式出发,就可以先求出小问题的解,最后大问题的解就出来了。如先求出f(3),f(4)...
代码:
class Solution { public int climbStairs(int n) { if(n<=0) return 0; if(n==1) return 1; if(n==2) return 2; /* 根据规则可以知道f(n)=f(n-1)+f(n-2);但是不能用递归,因为数字很大时,递归会超时。 这里其实是动态规划,思路还是根据上面的公式。一直从前往后加。自己在草稿纸上多写几项就知道规律了。 这里:one_step_before,表示f(n-1),two_step_before表示f(n-2).total表示f(n)。 比如,f(1)=1,f(2)=2,则f(3)=3,此时要算下一个f(4),f(4)=f(3)+f(2),所以对于f(4)而言,two_step_before=one_step_before(f2),one_step_before=total(f3); */ int one_step_before=2; int two_step_before=1; int total=0; for(int i=3;i<=n;i++){ total=one_step_before+two_step_before; two_step_before=one_step_before; one_step_before=total; } return total; } }