Leetcode 70. 爬楼梯 动规||递归

110 阅读3分钟

动规

70. 爬楼梯 - 力扣(LeetCode)

动规五部曲

状态表示

dp[n]表示到达第n层台阶有多少种方法

初始化

因为一次可以爬1个台阶(),2个台阶() dp[1]=1,dp[2]=2 (dp[1]表示爬一层台阶一种方法)(dp[2]表示爬2层台阶有2种方法)

转移方程

第三个台阶可以从第一个台阶跳两步跳上去

也可以从第二层台阶跳1步上去

到达第一个台阶只有一种方法,就是dp[1]

到达第二层台阶有两种方法,也就是dp[2]

所以到达第三层台阶有dp[3]=dp[1]+dp[2]=1+2=3种方法

因此状态转移方程为: dp[n]=dp[n-1]+dp[n-2];

返回值

要求到达n层台阶有多少种方法 返回dp[n]即可。

code

class Solution {
public:
    int climbStairs(int n) {



  vector<int> dp(n+1);

dp[1]=1;
dp[2]=2;

for(int i=3;i<=n;i++)
{
    dp[i]=dp[i-1]+dp[i-2];
    
}


return dp[n];
    }
};

image.png

因为有一种情况没考虑。假如n=1呢 dp[1]=dp[0]+dp[-1],而dp[0],dp[-1]我们又没初始化。

所以可以在开头再加个判断条件:

if(n<=1)return  n;

递归

这个是可以通过测试用例的,但是时间复杂度太大:

image.png

image.png

原因: 递归是一个树形结构:

image.png

如果是满二叉树的话,最大时间复杂度为O(2^n)

优化

不再计算重复的,直接拿计算过的来用: image.png

class Solution{
public:
    unordered_map<int,int> mp; // 声明一个无序哈希表,用于存储已经计算过的中间结果
    int climbStairs(int n) {   // 爬楼梯问题的解决方法,接收一个整数参数 n,返回到达顶部的方法数
        if(n == 1) return 1; // 基本情况:如果 n 是 1,直接返回 1,表示只有一种方法到达顶部(爬1步)
        if(n == 2) return 2; // 基本情况:如果 n 是 2,直接返回 2,表示有两种方法到达顶部(爬1步或者爬2步)

        auto it = mp.find(n); // 在哈希表中查找是否已经计算过 n 对应的结果
        if( it != mp.end() )  //it等于mp.end(),那就意味着已经到达了容器的末尾,不能再通过it来访问容器中的元素,所以我们让它!=end,先把map访问个遍,如果有重复的就不再计算,直接返回。
        
            return it->second;  //如果哈希表中已经存在键为n的元素,则直接返回对应的值。也就是说,如果之前已经计算过n对应的结果,那么可以直接返回这个结果,不需要再次进行递归计算。
 
        // 如果之前没有计算过,进入递归计算:
        int sum = climbStairs(n-1) + climbStairs(n-2); 
        mp.insert(pair<int, int> (n, sum)); // 将算过的的东西n和sum放到哈希里,下次遇到重复的了直接拿来用,可以减少计算。
        return sum; // 返回到达第 n 级楼梯的方法数
    }
};

具体来说,当函数第一次被调用时,它会检查`n`是否等于12。

如果是,它会直接返回对应的解。否则,它会查找`map`中是否

已经计算过当前`n`的解。如果已经计算过,它会直接从`map`中

获取存储的结果并返回。否则,它会递归计算`n-1``n-2`的解,

并将结果存储在`map`中,然后返回结果。