题目
You are climbing a stair case. It takes n steps to reach to the top.
Each time you can either climb 1 or 2 steps. In how many distinct ways can you climb to the top?
Note: Given n will be a positive integer.
Example 1:
Input: 2
Output: 2
Explanation: There are two ways to climb to the top.
1. 1 step + 1 step
2. 2 steps
Example 2:
Input: 3
Output: 3
Explanation: There are three ways to climb to the top.
1. 1 step + 1 step + 1 step
2. 1 step + 2 steps
3. 2 steps + 1 step
我的尝试
感觉是个递归问题,但是没有设计出递归方程,无法利用递归求解,也无法转化为动态规划问题。关键步骤没有搞定,后来看了一下思路,明白了状态转化方程,
求到达n的方式有几种,如果我们知道到达n-1有几种方式,到达n-2有几种方式,那么相加就是到达n有几种方式,因为这两个方案没有交集。n-1到n只能走一步,n-2到n走两步,如果后者走1+1这种方式,那么跟前者是重叠到。所以这两个方案没有交集。
来,尝试递归和DP解法解决这个题目。
递归思路
递归思路:
1. 转化方程或者说递归方式,理解: 1和2是基本单元,如果是5,利用基本单元可以分为(1,4),(2,3),因此递归方程就是
F(n)=F(n-1)+F(n-2)
2. 递归终止条件,如果n=1,返回1,如果n=2,则有两种可能,返回2(2,和1,1)
3 递归时间复杂度较高,递归方式在leetcode测试test case正常,但是会超时,一般递归方程写出来后,可以考虑利用DP方式解决。
class Solution {
public int climbStairs(int n) {
if(n==1){
return 1;
}
//写在一起,如果输入2,返回1,不对,明确基本单元结果,明确状态转化方程,递归的核心
if(n==2){
return 2;
}
return climbStairs(n-1)+climbStairs(n-2);
}
}
动态规划方法
class Solution {
public int climbStairs(int n) {
int[] dp = new int[n];
for (int i = 1; i <= n; i++) {
if (i == 1) {
dp[i - 1] = 1;
} else if (i == 2) {
dp[i - 1] = 2;
} else {
dp[i - 1] = dp[i - 2] + dp[i - 3];
}
}
return dp[n - 1];
}
}
其实就是个斐波那契数列问题,梳理后另一个写法,思路一样:
class Solution {
public int climbStairs(int n) {
if(n==1){
return 1;
}
int[] dp = new int[n];
dp[0]=1;
dp[1]=2;
for (int i = 2; i <n; i++) {
dp[i] = dp[i - 1] + dp[i - 2];
}
return dp[n-1];
}
}
节省空间的方法,最优方法:
class Solution {
public int climbStairs(int n) {
if(n==1) return 1;
if(n==2) return 2;
int one_stair=1;
int two_stair=2;
int ways=0;
for (int i = 3; i <=n; i++) {
ways=one_stair+two_stair;
one_stair=two_stair;
two_stair=ways;
}
return ways;
}
}