很经典的递归题,爬楼梯的方法=最后走1步+最后走2步,所以很容易就能写出递归算法。然而发现超时了,知道需要使用动态编程。其实上面的也是动态编程的思路,只不过动态编程将中间结果保存,这样其实遍历一次就能得到结果。
现在重新思考了一下动态编程和分治的相同于区别:
相同点:都需要寻找子问题,由子问题的解得到最终解
不同点:分治可能除了子问题,还需要额外的操作,有时候额外的操作时间复杂度甚至超过了子问题。分治一般不会保存中间结果,所以通常和递归结合使用。
动态编程必须明确找到子问题,并且子问题必须和原问题一样(目前遇到的都是一样的),动态编程必然存在一个递推关系(显示或者隐示的),显示的即可以直接用数学公式表示出来,隐示的需要找到一个DAG(有向无环图)。最终将问题转换为如何从起点走到终点的路径选择问题。
递归:
1 classSolution { 2 3 public: 4 5 int climbStairs(int n) { 6 7 if (n == 1) 8 9 return 1; 10 11 else if (n == 2) 12 13 return 2; 14 15 else 16 17 return climbStairs(n - 1) +climbStairs(n - 2); 18 19 20 21 } 22 23 };
动态规划:
1 class Solution { 2 3 public: 4 5 intclimbStairs(int n) { 6 7 intdp[200]; 8 9 dp[1]= 1; 10 11 dp[2]= 2; 12 13 for(int i = 3; i <=n; i++) 14 15 dp[i]= dp[i - 1] + dp[i - 2]; 16 17 returndp[n]; 18 19 20 21 } 22 23 };