题目描述:假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢? 注意:给定 n 是一个正整数。
示例 1:
输入: 2
输出: 2
解释: 有两种方法可以爬到楼顶。
- 1 阶 + 1 阶
- 2 阶
示例 2:
输入: 3
输出: 3
解释: 有三种方法可以爬到楼顶。
- 1 阶 + 1 阶 + 1 阶
- 1 阶 + 2 阶
- 2 阶 + 1 阶
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/climbing-stairs
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
方法一
递归法,模拟爬楼梯的这个过程,也就是暴力法
class Solution {
public int climbStairs(int n) {
//进入函数开始模拟,开始0层楼梯,还没开始爬
return climb_stairs(0,n);
}
public int climb_stairs(int i,int n)
{
//如果模拟的最后一步超过了楼梯最高,那么这次模拟无效,返回0
if(i>n)
return 0;
//如果正好可以爬完楼梯,模拟有效,加一
if(i==n)
return 1;
else
{
//函数递归
return climb_stairs(i+1,n)+climb_stairs(i+2,n);
}
}
}
如果自己用笔画出递归图的画,很容易可以看出,递归过程有反复在求解相同的部分,所以我们可以采用记忆化的思想来存储已经求解出并且以后用的上的部分
方法二
记忆化递归
用一个memo数组记忆递归中的解,下次如果还需要求解,直接取出来
class Solution {
public int climbStairs(int n) {
int [] memo=new int [n+1];
return climb_stairs(0,n,memo);
}
public int climb_stairs(int i,int n,int [] memo)
{
if(i>n)
return 0;
if(i==n)
return 1;
if(memo[i]>0)
return memo[i];
else
{
memo[i]=climb_stairs(i+1,n,memo)+climb_stairs(i+2,n,memo);
return memo[i];
}
}
}
方法三:
简单动态规划
首先分析一下题目
- 第i-1阶楼梯后向上爬一阶就可以到达i阶楼梯
- 第i-2阶楼梯向上爬两阶楼梯就可以到达i阶楼梯
所以可以看出到达第i阶楼梯的方法总数就是到达第i-1阶楼梯和到达第i-2阶楼梯的方法之和
-
定义状态
dp[i]表示到达第i阶的方法总数 -
状态转移方程
dp[i]=dp[i-1]+dp[i-2] -
分析初始值
dp[1]=1,第1阶楼梯的方法只有一个,就是爬一阶,
dp[2]=2,方法有两个,2=2+0,2=1+1.
代码实现
class Solution {
public int climbStairs(int n) {
if(n==1)
{
return 1;
}
int dp[] =new int[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];
}
}
方法四:
斐波那契数
算法
在上述方法中,我们使用 dp 数组,其中 dp[i]=dp[i−1]+dp[i−2]可以很容易通过分析得出 dp[i]其实就是第 i个斐波那契数。
Fib(n)=Fib(n−1)+Fib(n−2)
现在我们必须找出以 1 和 2 作为第一项和第二项的斐波那契数列中的第 n 个数,也就是说 Fib(1)=1 且 Fib(2)=2
public class Solution {
public int climbStairs(int n) {
if (n == 1) {
return 1;
}
int first = 1;
int second = 2;
for (int i = 3; i <= n; i++) {
int third = first + second;
first = second;
second = third;
}
return second;
}
}