先上题目:
70. 爬楼梯
假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
示例 1:
输入:n = 2
输出:2
解释:有两种方法可以爬到楼顶。
1. 1 阶 + 1 阶
2. 2 阶
示例 2:
输入:n = 3
输出:3
解释:有三种方法可以爬到楼顶。
1. 1 阶 + 1 阶 + 1 阶
2. 1 阶 + 2 阶
3. 2 阶 + 1 阶
来源:力扣(LeetCode)
分析:
到楼顶,即最高阶的方法总数会等于“上一步是爬1阶”的方法总数和“上一步是爬2阶”的方法总数相加。每一阶都如此。
值得注意的是,上第一阶有1种方法,上第二阶有2种方法,上第三阶以及以上有“前两阶方法总数相加”的方法。
图片来源:图灵
解法:
这里提供了三个解法,分别是:递归、动态规划和斐波那契公式。
class Solution {
//1.递归写法
//直接使用递归会超时
//使用数组/集合记录已经计算出来的数,减少重复计算的时间
//时间复杂度:O(n)
HashMap<Integer, Integer> map = new HashMap<>();
public int climbStairs1(int n) {
if(n == 1){
return 1;
}
if(n == 2){
return 2;
}
if(map.get(n) != null){
return map.get(n);
} else{
int result = climbStairs(n - 1) + climbStairs(n - 2);
map.put(n, result);
return result;
}
}
//2.循环/动态规划写法
//也可以使用数组,不过会增加空间复杂度
//在c中,++i效率比i++高,因为i++多了一步(temp = i);而在java,二者都用到了中间值temp,即它们的效率是一样的。
//时间复杂度:O(n)
public int climbStairs2(int n) {
if(n == 1){
return 1;
}
if(n == 2){
return 2;
}
int result = 0;
int prepre = 1;
int pre = 2;
for(int i = 3;i <= n;i++){
result = prepre + pre;
prepre = pre;
pre = result;
}
return result;
}
//3.斐波那契数列写法
//斐波那契数列:第0个数为0,第一个数为1,第二个数为1,从第三项(2)开始,每一项都为前两项之和
//时间复杂度:O(logn)
public int climbStairs3(int n) {
double sqrt_5 = Math.sqrt(5);
double fib_n = Math.pow((1 + sqrt_5) / 2, n + 1) - Math.pow((1 - sqrt_5) / 2,n + 1);
return (int)(fib_n / sqrt_5);
}
}
附上:斐波那契公式: