1、问题分析
题目链接:https://leetcode-cn.com/problems/three-steps-problem-lcci/
可以使用动态规划解决,状态转移方程是:dp[i] = dp[i-1] + dp[i-2] + dp[i-3]
,最重要的还是数据太大,导致的溢出问题。代码我已经进行了详细的注释,理解应该没有问题,读者可以作为参考,如果看不懂(可以多看几遍),欢迎留言哦!我看到会解答一下。
2、问题解决
笔者以C++
方式解决。
#include "iostream"
using namespace std;
#include "algorithm"
#include "vector"
#include "queue"
#include "set"
#include "map"
#include "cstring"
#include "stack"
class Solution {
private:
// 定义最大楼梯个数
const static int MAXN = 1000001;
// dp[i] 代表 i 阶楼梯有多少种走法,初始化为0
// dp[i] = dp[i-1] + dp[i-2] + dp[i-3]
// 也就是最后一步走 1 步,或2步或3步的和
int dp[MAXN] = {0};
public:
int waysToStep(int n) {
int i = init(n);
return i;
}
/**
* 获取第 index 阶楼梯有多少种走法
* @param index
* @return
*/
int init(int index) {
if (index <= 0) {
return 0;
}
// 如果前面计算出了结果,直接返回
if (dp[index] != 0) {
return dp[index];
}
// 递归边界
if (index == 1) {
dp[index] = 1;
return dp[index];
}
if (index == 2) {
dp[index] = 2;
return dp[index];
}
if (index == 3) {
dp[index] = 4;
return dp[index];
}
//取模,对两个较大的数之和取模再对整体取模,防止越界(这里也是有讲究的)
//假如对三个dp[i-n]都 % 1000000007,那么也是会出现越界情况(导致溢出变为负数的问题)
//因为如果本来三个dp[i-n]都接近 1000000007 那么取模后仍然不变,但三个相加则溢出
//但对两个较大的dp[i-n]:dp[i-2],dp[i-3]之和mod 1000000007,那么这两个较大的数相加大于 1000000007但又不溢出
//取模后变成一个很小的数,与dp[i-1]相加也不溢出
//所以取模操作也需要仔细分析
// ------------------------------------上面是参考 LeetCode题解的 -------------------------------
// 下面说说我遇到的问题,我刚刚开始想,反正数很大是吧,那就霸王硬上弓,我直接来个 unsigned long long 不就可以了,还是 too young too simple
// unsigned long long 还是会越界,但是不会报溢出异常,如果溢出了,就相当于取模2^64了。望后来的人少踩坑
dp[index] = ((init(index - 1) + init(index - 2)) % 1000000007 + init(index - 3)) % 1000000007;
return dp[index];
}
};
int main() {
int n = 76;
Solution *pSolution = new Solution;
int i = pSolution->waysToStep(n);
cout << i << endl;
system("pause");
return 0;
}
运行结果
有点菜,有时间再优化一下。
3、总结
书上的代码直接运行绝大部分是对的,但是总有一些软件的更新使得作者无能为力。之前的API是对的,但是之后就废弃了或修改了是常有的事。所以我们需要跟踪源代码。这只是一个小小的问题,如果没有前辈的无私奉献,很难想象我们自己一天能学到多少内容。感谢各位前辈的辛勤付出,让我们少走了很多的弯路!
点个赞再走呗!欢迎留言哦!