【LeetCode & 剑指offer刷题】动态规划与贪婪法题1:70 Climbing Stairs

【LeetCode & 剑指offer 刷题笔记】目录(持续更新中...)

70. Climbing Stairs

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
 
//问题:爬楼梯(每次只能爬1步或者2步)
//分析:具有最优子结构和重叠子问题的两点特性,可以用动态规划方法
//暴力法:递归分解climbStairs(i,n)=(i+1,n)+climbStairs(i+2,n),由于存在很多重复子问题,效率很低,时间复杂度为O(2^n)(递归二叉树结点数)
/*
//方法一:带备忘的自顶向下法(O(n),O(n))
//分解问题:climbStairs(i,n)=(i+1,n)+climbStairs(i+2,n),i为当前的步子,n为目标的步子
class Solution
{
public:
    int climbStairs(int n)
    {
        vector<int> memo(n);
        return climb_stairs(0, n, memo); //递归
    }
    int climb_stairs(int i, int n, vector<int>& memo)
    {
        if(i>n) return 0; //后面分解的时候有i+1和i+2,故有可能出现i>n的情况
        if(i==n) return 1; //初始值
        if(memo[i] > 0) return memo[i];//已经计算的不必重新计算
        memo[i] = climb_stairs(i+1, n, memo) + climb_stairs(i+2, n, memo);//每一次只能爬一步或两步
        return memo[i];
    }
};*/
//方法二:自底向上法(O(n),O(n))
//通项公式:可以从坐标(i-1)到坐标i,也可以从坐标(i-2)到坐标i,
//故有dp[i]=dp[i−1]+dp[i−2],dp[i]表示到坐标i的走法,所以可以从按问题规模从小到大计算,这样就不会计算重复问题了 (可以写出递推公式,自上而下分析,自下而上解决)
//思路:考虑到坐标n,有两种情况,在n-1级台阶上往上跳1级,在n-2级台阶上往上跳2级,故得an = an-1 + an-2,可以推广到其他位置
class Solution
{
public:
    int climbStairs(int n
    {
        if(n <= 0) return 0;
        if(n == 1) return 1;//因为通项公式中最少须有两个初始值
 
        vector<int> dp(n+1); //初始化为0
        dp[0] = 1; dp[1] = 1;
        for(int i = 2; i<=n; i++) dp[i] = dp[i -1] + dp[i-2]; //假设dp[0]=1,则从dp[2]开始满足通项公式
        return dp[n];
       
    }
};
//方法三:斐波那契数列(O(n),O(1)) 计算时只保存三个数,故可节省空间(方法二也可以做此优化)
//方法四:Binets Method(O(logn),O(1)) [[Fn+1 Fn], [Fn Fn-1]] = [[1 1], [1 0]]^n
 
延伸1:(变态跳台阶)
    如果这个青蛙可以跳1级、2级...n级,则跳上n级台阶有多少种跳法
思路:跳到n级台阶,an = an-1 + an-2 +....a1 +a0 (a0 = 1,表示从起点一次性跳n级,a1 =1, a2 =2),由数学归纳法可以证明an = 2^(n-1)
 
延伸2:矩形覆盖 
    我们可以用2*1的小矩形横着或者竖着去覆盖更大的矩形。请问用n个2*1的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法?
 
/*
问题:矩形覆盖
方法:动态规划
f(n)表示2*n的矩形的覆盖方法
f(n)可以是2*(n-1)的矩形加一个竖着放的2*1的矩形或2*(n-2)的矩形加2横着放的,
故递推公式为:f(n)=f(n-1)+f(n-2)
另外,f(1)=1,f(2)=2,为方便起见,假设f(0) = 1
*/
class Solution
{
public:
    int rectCover(int n)
    {
        if(n <= 0) return 0;
        if(n == 1) return 1;
       
        vector<int> dp(n+1);
        dp[0] = dp[1] = 1;
        for(int i = 2; i<=n; i++)
            dp[i] = dp[i-1] + dp[i-2];
       
        return dp[n];
    }
};
 

 

posted @ 2019-01-05 20:18  wikiwen  阅读(200)  评论(0编辑  收藏  举报