题目
链接:leetcode-cn.com/problems/qi…
一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶。求该青蛙跳上一个 n 级的台阶总共有多少种跳法。
答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。
示例 1:
输入:n = 2
输出:2
示例 2:
输入:n = 7
输出:21
示例 3:
输入:n = 0
输出:1
题解:
- 递归 首先想得到的思路是递归,把问题F(n)分解成F(n-1)和F(n-2)两个部分,当n=0和1的时候返回1,n=2返回2,其余则递归。代码如下
function numWays(int n) {
return Ways(n);
}
function Ways(int n){
if(n <= 1){
return 1;
}
if( n == 2){
return 2;
}
return (Ways(n-1) % 1000000007) + (Ways(n-2) % 1000000007);
}
但是递归存在众多的重复操作,有严重的性能问题。的确也出现了运行超时不通过。
- 备忘录 减少重复的工作的方法就是将已经计算过的数值保存起来。 这就是备忘录的核心工作,本质就是空间换时间。
var numWays = function (n) {
let cache = new Array(n + 1).fill(-1); ///备忘录
count(n, cache); // 填充备忘录
return cache[n];
};
function count(n, cache) {
if (n <= 1) cache[n] = 1;
if (n === 2) cache[n] = 2;
if (cache[n] !== -1) return cache[n];
else cache[n] = (count(n - 1, cache) + count(n - 2, cache)) % 1000000007;
return cache[n];
}
- 动态规划 很明显,青蛙跳台阶的问题就是斐波那契数列问题
- 状态定义: 设 dpdp 为一维数组,其中 dp[i] 就是青蛙跳上一个 n 级的台阶总共跳法数
- 转移方程: dp[i + 1] = dp[i] + dp[i - 1] ,即对应数列定义 f(n + 1) = f(n) + f(n - 1) ;
- 初始状态: dp[0] = 1dp[0]=1, dp[1] = 1dp[1]=1 ,即初始化前三个数字;
- 返回值: dp[n] ,青蛙跳上一个 n 级的台阶跳法数
var numWays = function(n) {
if (n == 0 || n == 1) {
return 1;
}
// 初始状态
let dp=[];
dp[1] = 1;
dp[2] = 2;
// 状态转移
for (int i = 3; i <= n; i++) {
dp[i] = (dp[i - 2] + dp[i - 1]) % 1000_000_007;
}
return dp[n];
}
- 动态规划优化 其实很久状态转移方程我们也可以很清楚的看出来,dp[n]只跟前两项即dp[n-1], dp[n-2]有关,既然如此那么我们就不需要申请那么多空间,直接用两个变量来表示前两项就可以了。
var numWays = function(n) {
if (n == 0 || n == 1) {
return 1;
}
// 两个变量表示前两项
let pre = 1, cur = 2;
for (let i = 3; i <= n; i++) {
let tmp = (pre + cur) % 1000_000_007;
// 更新变量,以便继续求解
pre = cur;
cur = tmp;
}
return cur;
};