爬楼梯会累问题的解法(C++)

问题

大概是说小红要爬楼梯,一次可以爬一节台阶、或者两节、三节,但是如果一次上两节或者三节会累,所以在一次上完两节或三节之后只能上一节。问上n节台阶,一共有几种方案,n<=80。

这个问题在网上没有找到相关的解法。自己想到了两种方法,回溯和两个一维数组的动态规划。跟大佬讨论后得到了一个精简一维数组解法。

  • 回溯会超过1000ms
  • 一维动规很快

记录一下:

凡人解法

#include <bits/stdc++.h>
using namespace std;

class Solution1 {
    
    //回溯法
public:
    long long ans = 0;
    void backTracking(int n, bool only1) {
    
    
        if (n == 0) {
    
    
            ++ans;
            return;
        }
        if (n < 0) return;
        if (!only1) {
    
    
            backTracking(n - 2, true);
            backTracking(n - 3, true);
        }
        backTracking(n - 1, false);
        return;
    }
    long long climb_stairs(int n) {
    
    
        // write code here
        if (n == 1) return 1;
        backTracking(n, false);
        return ans;
    }
};

class Solution2 {
    
    //2个一维dp
public:
    
    long long dpdp(int n) {
    
    
        if (n <= 2) return n;
        vector < vector<int>> dp(2, vector<int>(n + 1, 0));
        dp[0][0] = dp[0][1] = 0;
        dp[0][2] = dp[1][2] = dp[1][0] = dp[1][1] = 1;
        for (int i = 3; i <= n; ++i) {
    
    
            dp[0][i] = dp[1][i - 2] + dp[1][i - 3];
            dp[1][i] = dp[0][i - 1] + dp[1][i - 1];
        }
        return dp[0][n] + dp[1][n];
    }
};

void main()
{
    
    
       
    for (int i = 1; i <= 80; i++) {
    
    
        Solution1 s1;
        Solution2 s2;
        if (s1.climb_stairs(i) == s2.dpdp(i)) cout << "n=" << i << "solved rightly!" << endl;        
    }
}

大佬一步到位

以结果为导向,dp[i] 的含义是走到第i层的方案数

  • ①不考虑会累的限制:
    • 到i层的这一步的有3种通常情况: 走了1步到i,走了2步到i,走了3步到i
  • ②考虑会累的限制:
    • 走2步或走3步的前提是没有累,所以此前必然是只走了1步,可以归纳为走了1+2=3步,或走了1+3步=4步。
    • 如果走了2步或者3步,后续必然会累只能走1步,可以归纳为走了2+1=3步或走了
      3+1=4步

所以上述通常情况1,2,3步变成了1,3,4步

注意: ②中的2+1=3的情况和3+1=4的情况应该归纳到了只走了1步的情况,因为

  • 我们写等式时dp[i] += dp[i-1]的意思是,自加 走了1步刚好到第i层的情况(走1步与之前状态无关,包括2+1,3+1,1+1)
  • dp[i] += dp[i-3] 的意思是,自加 走了3步刚好到第i层的情况(包括的是先走2步再走1步)
  • dp[i] += dp[i-4] 的意思是,自加 走了4步刚好到第i层的情况(包括的是先走3步再走1步)
class Solution3 {
    
    
public:

    long long dpdp(int n) {
    
    
        vector<long long > dp(n + 2, 0);
        //long long dp[80];
        //memset(dp, 0, sizeof dp);
        dp[0] = 1;
        for (int i = 1; i <= n+1; ++i) {
    
    
            dp[i] += dp[i - 1];
            if (i >= 3) dp[i] += dp[i - 3];
            if (i >= 4) dp[i] += dp[i - 4];
        }
        return dp[n+1];
    }
};

猜你喜欢

转载自blog.csdn.net/weixin_44671418/article/details/125962529