你在爬楼梯,需要n步才能爬到楼梯顶部
每次你只能向上爬1步或者2步。有多少种方法可以爬到楼梯顶部?
//斐波那契数列 class Solution { public: int climbStairs(int n) { //递归方法,时间不够。。。 /*if (n <= 1) return 1; return climbStairs(n-1) + climbStairs(n-2); */ //非递归方法,自己在for循环里面模拟递归 int result = 1, pre = 0; for (int i = 1; i <= n; i++) { int tmp = result; result += pre; pre = tmp; } return result; } };
public class Solution { /* 暴力递归 此题超时 public int climbStairs(int n) { if(n == 1) return 1; if(n == 2) return 2; return climbStairs(n - 1) + climbStairs(n -2); } */ //常规时间复杂度O(n)算法 public int climbStairs(int n) { if(n == 2) return 2; if(n == 1) return 1; int tmp = 0; int pre = 1; int res = 2; for(int i = 3; i <= n; i++){ tmp = res; res = res + pre; pre = tmp; } return res; } /* //动态规划 空间和时间复杂度都为O(n), public int climbStairs(int n) { int[] dp = new int[n + 1]; dp[0] = 1; dp[1] = 1; for(int i = 2; i <= n; i++){ dp[i] = dp[i - 1] + dp[i - 2]; } return dp[n]; } */ }
# # # @param n int整型 # @return int整型 # class Solution: def climbStairs(self , n ): # write code here if n <= 2: return(n) else: dp = [0 for x in range(n+1)] dp[1],dp[2] = 1,2 for i in range(3,n+1): dp[i] = dp[i-1]+dp[i-2] return(dp[-1])
Leetcode#70. Climbing Stairs(爬楼梯)
package DynamicProgramming;
/**
* 70. Climbing Stairs(爬楼梯)
* 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
* 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
*/
public class Solution70 {
public static void main(String[] args) {
Solution70 solution70 = new Solution70();
System.out.println(solution70.climbStairs(3));
}
/**
* 直接用递归
*
* @param n
* @return
*/
public int climbStairs(int n) {
if (n <= 2) {
return n;
} else {
return climbStairs(n - 1) + climbStairs(n - 2);
}
}
/**
* 用迭代的方法,用两个变量记录f(n-1) f(n-2)
*
* @param n
* @return
*/
public int climbStairs_2(int n) {
int one = 1, two = 2, fN = 0;
if (n <= 0) {
return 0;
} else if (n <= 2) {
return n;
} else {
for (int i = 3; i <= n; i++) {
fN = one + two;
one = two;
two = fN;
}
return fN;
}
}
}
//本质为斐波拉契数列 //1.假设当有n个台阶时假设有f(n)种走法。 //2.青蛙最后一步要么跨1个台阶要么跨2个台阶。 //3.当最后一步跨1个台阶时即之前有n-1个台阶,根据1的假设即n-1个台阶有f(n-1)种走法。 //4. 当最后一步跨2个台阶时即之前有n-2个台阶,根据1的假设即n-2个台阶有f(n-2 )种走法。 //5.显然n个台阶的走法等于前两种情况的走法之和即f(n)=f(n-1)+f(n-2)。 public int climbStairs(int n) { if(n<0) return -1; if(n ==0 ||n==1 || n==2) return n; int first = 1,second = 2,third = 0; for(int i = 3;i<=n;i++){ third = first + second; first = second; second = third; } return third; }
二刷这道题,其实方法三还可以继续进行优化,后续会把具体算法【解法四】补上
现在说一下大致思路:求出递推公式
f(n)=f(n-1)+f(n-2) ===>f(n)+f(n-1)=2f(n-1)+f(n-2)
[f(n) f(n-1)]=[[1 1][1 0]][f(n-1) f(n-2)]
可以得到递推矩阵
所以该算法的关键点就是:1.需要求出递推矩阵;2.写一个方法,能够实现矩阵相乘
虽然代码量会比其他几个方法大,但是算法复杂度比较低
/*
* 动态规划解法
*/
public int climbStairs3(int n) {
if (n <= 0)
return 0;
if (n == 1)
return 1;
if (n == 2)
return 2;
int[][] base = { { 1, 1 }, { 1, 0 } };
int[][] res = matrixPower(base, n - 2);
return 2*res[0][0] + res[1][0];
}
/*
* 求矩阵m的p次方
*/
public int[][] matrixPower(int[][] m, int p) {
int[][] res = new int[m.length][m[0].length];
// 把res设为单位矩阵,相当于整数中的1;
for (int i = 0; i < res.length; i++) {
res[i][i] = 1;
}
int[][] tmp = m;
for (; p != 0; p >>= 1) {
if ((p & 1) != 0)
res = muliMatrix(res, tmp);
tmp = muliMatrix(tmp, tmp);
}
return res;
}
/*
* 两个矩阵相乘
*/
private int[][] muliMatrix(int[][] m1, int[][] m2) {
int[][] res = new int[m1.length][m2[0].length];
for (int i = 0; i < m1.length; i++) {
for (int j = 0; j < m2[0].length; j++) {
for (int k = 0; k < m2.length; k++) {
res[i][j] += m1[i][k] * m2[k][j];
}
}
}
return res;
}
//包含三种最常用的回答,第一最优,第三最差 ,
/*
* 空间复杂度O(1);
*/
public int climbStairs(int n) {
if (n < 3)
return n;
int one_step_before = 2;
int two_steps_before = 1;
int all_ways = 0;
for (int i = 2; i < n; i++) {
all_ways = one_step_before + two_steps_before;
two_steps_before = one_step_before;
one_step_before = all_ways;
}
return all_ways;
}
/*
* 空间复杂度O(n);
*/
public int climbStairs_2(int n) {
if (n < 3)
return n;
int[] res = new int[n + 1];
res[1] = 1;
res[2] = 2;
for (int i = 3; i <= n; i++) {
res[i] = res[i - 1] + res[i - 2];
}
return res[n];
}
/*
* 方法一:递归 时间复杂度高
*/
public int climbStairs_1(int n) {
if (n < 1)
return 0;
if (n == 1)
return 1;
if (n == 2)
return 2;
return climbStairs_1(n - 1) + climbStairs_1(n - 2);
}
```
/* 思路:动态规划 和斐波那契数列相同的思路。 第三节楼梯有两种抵达方式: 1.从第1节直接走两步 2.从第2节走一步 因此爬到第3节的方法数变成了:爬到第一节+爬到第二节的方法数 状态定义: f0:第i-2节楼梯的方法数 f1:第i-1节楼梯的方法数 f2:第i节楼梯的方法数 状态转移方程: f2 = f1 + f0; f0 = f1; f1 = f2; */ class Solution { public: /** * * @param n int整型 * @return int整型 */ int climbStairs(int n) { //前三层的可以直接算出来,因此可以直接返回 if(n <= 3){ return n; } int f1 = 1; int f2 = 2; int f3; //利用动态规划计算 for(int i=3;i<=n;i++){ f3 = f1+f2; f1 = f2; f2 = f3; } return f3; } };
Erlang动态规划拆分情况
解题思路
因为每次只能爬1或2个台阶, 从1个2个台阶开始推断, 并将问题n阶台阶拆解为求解到达n-1阶台阶以及n-2阶台阶的总和, 过程中缓存已记录阶数对应的数据
代码
-spec climb_stairs(N :: integer()) -> integer(). climb_stairs(N) when N =< 2 -> N; climb_stairs(N) -> do_climb_stairs(3, #{stairs => N, 1 => 1, 2 => 2}). do_climb_stairs(N, Args = #{stairs := Stairs}) when N < Stairs -> Sum = maps:get(N - 1, Args) + maps:get(N - 2, Args), do_climb_stairs(N + 1, Args#{N => Sum}); do_climb_stairs(N, Args) -> maps:get(N - 1, Args) + maps:get(N - 2, Args).
class Solution { public: /** * * @param n int整型 * @return int整型 */ int climbStairs(int n) { // write code here //f(n)=f(n-1)+f(n-2),f(0)=1,f(1)=1,f(2)=2,f(3)=3 //动态规划,非递归 if(n==0||n==1) return 1; int a=1,b=1,c; for(int i=2;i<=n;i++){ c=a+b; a=b; b=c; } return c; } };
class Solution { public: #include <cstring> void mul(int c[][2], int a[][2], int b[][2]){ static int tmp[2][2] = {0, 0, 0, 0}; memset(tmp, 0, sizeof tmp); for(int i = 0; i < 2; ++ i) for(int j = 0; j < 2; ++ j) for(int k = 0; k < 2; ++ k) tmp[i][j] += a[i][k] * b[k][j]; memcpy(c, tmp, sizeof tmp); } void qmi(int a[][2], int b[][2], int k){ while(k){ if(k & 1) mul(a, a, b); mul(b, b, b); k >>= 1; } } int climbStairs(int n) { int F[2][2] = {1, 1, 0, 0}; int a[2][2] = {1, 1,1, 0}; qmi(F, a, n - 1); return F[0][0]; } };
public int climbStairs (int n) { // write code here // 斐波那契数列 // 动态规划 //if (n <= 3) { // return n; //} //int dp[] = new int[n]; //dp[0] = 1; //dp[1] = 2; //dp[2] = 3; //for (int i = 2; i < n; i++) { // dp[i] = dp[i - 1] + dp[i - 2]; //} //return dp[n-1]; // 压缩状态 int a = 0, b = 0, c = 1; for (int i = 0; i < n; i++) { a = b; b = c; c = a + b; } return c; }