746. 使用最小花费爬楼梯
1. 题目描述
题目链接
假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
注意:给定 n 是一个正整数。
示例 1:
输入: 2
输出: 2
解释: 有两种方法可以爬到楼顶。
1. 1 阶 + 1 阶
2. 2 阶
示例 2:
输入: 3
输出: 3
解释: 有三种方法可以爬到楼顶。
1. 1 阶 + 1 阶 + 1 阶
2. 1 阶 + 2 阶
3. 2 阶 + 1 阶
2. 题目分析
如果第一次遇到这种问题,无从下手的时候,就列出前几项找规律,看看有没有数列的规律。
n表示楼梯数, f(n) 表示爬楼梯的可能方法数;
找规律:
n=1, f(n) = 1;
n=2, f(n) = 2;
n=3, f(n) = 3;
n=4, f(n) = 5;
…
n=n, f(n) = f(n-2) + f(n-1) ;
根据规律,我们发现这其实是有规律的,就是f(n) = f(n-2) + f(n-1);看到这个状态转移方程,想到什么?这不是斐波那契数列吗?那么接近斐波那契数列首先想到的解决方法什么?递归,只要几句话就能轻松求解该问题。但前面说了,如果题目对时间复杂度和空间复杂度有要求,最好不要用递归这种自上而下的方法,可以使用递推方法,即自下而上寻求解。
其实这是一种动态规划问题,对于该类型问题,可以自上而下寻找解决思路,然后用自下而上的备忘录方法存储中间值,从而减少回溯的次数,从而达到减少时间复杂度和空间复杂度。
3. 解决思路
状态:result[i]表示到达第i个阶梯需要的最小花费。
状态转移方程:f(n) = f(n-1)+f(n-2);
4. 代码实现(java)
- 递归方法实现
/**
* 方法一:递归实现,每次爬楼梯时,可以选择爬1阶楼梯,也可以爬2阶楼梯,
* 所以假设这次爬楼梯的可能有f(n)种,那么这次爬完的可能性就有,f(n-1)+f(n-2)种,因为还剩下的阶梯有可能是n-1,也有可能是n-2;
* 耗时慢
* @param n
* @return
*/
public static int climbStairs(int n) {
if (n == 1){
return 1;
}
if (n == 2){
return 2;
}
return climbStairs(n-1)+climbStairs(n-2);
}
- 递推方法实现
package com.algorithm.leetcode.dynamicAllocation;
/**
* Created by 凌 on 2018/12/11.
* 描述:70. 爬楼梯
* 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
*/
public class ClimbStairs {
public static void main(String[] args) {
int n = 1;
Long lastTime = System.currentTimeMillis();
int result = climbStairs_1(n);
Long currentTime=System.currentTimeMillis();
System.out.println("结果:"+result + "->耗时:"+(currentTime-lastTime));
lastTime = System.currentTimeMillis();
result = climbStairs(n);
currentTime=System.currentTimeMillis();
System.out.println("结果:"+result + "->耗时:"+(currentTime-lastTime));
}
/**
* 非递归方法
* @param n
* @return
*/
public static int climbStairs_1(int n) {
if (n == 1){
return 1;
}
if (n == 2){
return 2;
}
int[] temp = new int[n+1];
temp[1] = 1;
//前面必须判断n是否大于1,如果n=1,那么temp[2]则会越界
temp[2] = 2;
for (int i = 3; i < n+1; i++) {
temp[i] = temp[i-1] + temp[i-2];
}
return temp[n];
}
}