青蛙跳台阶的相关问题
问题一:青蛙一次只能跳 1 个台阶或者 2 个台阶, 计算从 0 台阶跳到 n 台阶有多少跳法,也就是的路径种类总和。
import java.util.HashMap;
public class StepJump {
// 当青蛙只能跳 1 个台阶或者 2 个台阶, 计算从 0 台阶跳到 n 台阶的路径种类总和
// 这个类似斐波那契数列 1 1 2 3 5 8 13
// f(0)=1, f(1)=1, f(2)=f(0)+f(1),[其中f(0)表示从0阶直接跳到2阶] f(3)=f(1)+f(2)
// f(3)=f(1)+f(2)的解释:[先跳到1阶的路径种类(然后直接跳到3阶)+先跳到2阶的路径种类(然后直接跳到3阶)]
private static int fun1(int n) {
if(n < 2)
return 1;
// [先跳到n-1阶的路径种类(然后直接跳到n阶)+先跳到n-2阶的路径种类(然后直接跳到n阶)]
return fun1(n-1)+fun1(n-2); // 递归
}
// 避免重复计算,可用一个 HashMap 存储计算过的值,防止重复计算。
private static int fun2(int n, HashMap<Integer, Integer> map) {
if(n < 2)
return 1;
// 如果map包含 n 对应的值,直接返回
if(map.containsKey(n))
return map.get(n);
// 递归求值,和fun1()同样道理
int first = fun2(n-1, map);
int second = fun2(n-2, map);
int sum = first + second;
// 储存值,方便下次寻找
map.put(n, sum);
return sum;
}
// 利用循环计算,效率更高
private static int fun3(int n) {
if(n < 2)
return 1;
int first = 1, second = 1, sum = 0;
while(n-- >= 2) {
sum = first + second;
first = second;
second = sum;
}
return sum;
}
public static void main(String[] args) {
int n = 40;
long time = System.nanoTime();
System.out.println(fun1(n));
System.out.println("递归时间:" + (System.nanoTime() - time));
time = System.nanoTime();
System.out.println(fun2(n, new HashMap<Integer, Integer>()));
System.out.println("HashMap时间:" + (System.nanoTime() - time));
time = System.nanoTime();
System.out.println(fun3(n));
System.out.println("循环时间:" + (System.nanoTime() - time));
}
}
问题二:青蛙一次能跳 1 到 n 个台阶, 计算从 0 台阶跳到 n 台阶有多少跳法,也就是的路径种类总和。
public class StepJumpTwo {
// 青蛙一次能跳 1 到 n 个台阶, 计算从 0 台阶跳到 n 台阶的路径种类总和
// f(n) = f(n-1)+f(n-2)+......+f(1)+f(0)------a式子
// f(n-1)= f(n-2)+f(n-3)+......+f(1)+f(0)------b式子
// (a式子)-(b式子)得 f(n)-f(n-1)=f(n-1)
// 最终得到 f(n)=2*f(n-1)的等比数列,该等比数列为2^(n-1)
private static int fun(int n){
if(n < 2)
return 1;
return 1<<(n-1); // 位运算,速度更快
}
public static void main(String [] args){
System.out.println(fun(10));
}
}
问题三:青蛙一次能跳 1 到 m 个台阶, 计算从 0 台阶跳到 n 台阶有多少跳法,也就是的路径种类总和。
public class StepJumpThree {
// 青蛙一次能跳 1 到 m 个台阶, 计算从 0 台阶跳到 n 台阶的路径种类总和
// 情况1 n <= m 时,也就回到了问题二 f(n)=2*f(n-1), 等比数列为2^(n-1)
// 情况2 当 n-1 = m 时
// f(n) = f(n-1)+f(n-2)+......+f(2)+f(1) 接下所有的计算又回到情况1
// = 2*f(n-2)+2*f(n-3)+......+2*f(1)+f(1)
// = ......
// = 2^(n-1)-1 (f(n)=2*f(n-1)的等比数列[2^(n-1)]的前 n-1 项和[2^(n-1)-1]
// 情况3 当 n-1 > m 时
// f(n) = f(n-1)+f(n-2)+......+f(n-m+1)+f(n-m)------a式子
// f(n-1)= f(n-2)+f(n-3)+......+f(n-m)+f(n-1-m)------b式子
// (a式子)-(b式子)得 f(n)-f(n-1)=f(n-1)-f(n-1-m)
// 最终得到 f(n)=2*f(n-1)-f(n-1-m)
private static int fun(int n, int m){
if(n < 2)
return 1;
if(n <= m) // 情况1
return 1<<(n-1);
if(n-1 == m) // 情况2
return (1<<(n-1))-1;
// 情况3
return 2*fun(n-1, m)+fun(n-1-m, m);
}
public static void main(String [] args){
System.out.println(fun(1, 5)); // n < 2
System.out.println(fun(4, 5)); // 情况1
System.out.println(fun(6, 5)); // 情况2
System.out.println(fun(7, 5)); // 情况3
}
}