问题:有n步台阶,一次只能上1步或2步,共有多少种走法?
解法:
(1)递归
(2)循环迭代
递归
注:对于每一种我们只关心他最后一步的两种可能,一种是还差一步,一种是还差两步,这两种可能相加就可以(关心他最后是 一步跨两个台阶 还是 一步跨一个台阶。
解释:假设当n=3时,他跨完所有台阶有两种情况,一种是最后一次是踏一步踏完台阶,另一种是最后一次踏两步踏完台阶,图中n=3时的两种情况就是如此。
图中演示的并不是:
第一种情况:踏一步-踏一步-踏一步-踏完
第二种情况:踏一步-踏两步-踏完
第三种情况:踏两步-踏一步-踏完
n=1时有多少种走法,n=2时有多少种走法,这两种加起来就是n=3时有多少种走法。f(2)里包含了f(1),f(n)最后一次的走法往前推,最后一次的走法要么是n-1步,要么是n-2步。即要么走一步要么走2步,由此引入f(n-1)和f(n-2),f(n)=f(n-1)+f(n-2),由大往小调,大的不断调用小的,一步一步往前推。
)
代码如下:
package org.example.step;
import org.junit.Test;
public class TestStep{
@Test
public void test(){
long start = System.currentTimeMillis();
System.out.println(f(100));//165580141
long end = System.currentTimeMillis();
System.out.println(end-start);//586ms
}
// 实现f(n):求n步台阶,一共有几种走法
// f(n)=f(n-1)+(n-2)
public int f(int n){
if(n<1){
throw new IllegalArgumentException(n + "不能小于1");
}
if(n==1 || n==2){
return n;
}
return f(n-2) + f(n-1);
}
}
循环迭代:
注:one和two作为变量把状态保存了,两种方法看似相同,很大不同。递归是倒推,大的不断往前得到小的。循环迭代是顺推,小的累积得到大的。
代码如下:
package org.example.step;
import org.junit.Test;
public class TestStep2 {
@Test
public void test(){
long start = System.currentTimeMillis();
System.out.println(loop(100));//165580141
long end = System.currentTimeMillis();
System.out.println(end-start);//<1ms
}
public int loop(int n){
if(n<1){
throw new IllegalArgumentException(n + "不能小于1");
}
if(n==1 || n==2){
return n;
}
/*
* 对于下面两行结合图来看,图中显示 two = f(1); one = f(2)
* f(1)指跨1步,f(2)指跨2步
* */
int one = 2;// 初始化为到达共3级台阶跨2步台阶还差1步台阶的走法(初始化为走到第二级台阶的走法--原文)
int two = 1;// 初始化为到达共3级台阶跨1步台阶还差2步台阶的走法(初始化为走到第一级台阶的走法--原文)
// 定义一个参数,赋值0仅是初始化一下
int sum = 0;
for(int i=3; i<=n; i++){
// 最后跨2步 + 最后跨1步的走法
sum = two + one;
// two = n-1 时的one,one = n-1 时的sum
two = one;
one = sum;
}
return sum;
}
}
对于上面两种方法的总结:
(1)递归相较于循环迭代效率低,但简洁易懂;循环迭代相较于递归效率高,但稍微复杂一些,且不易理解。
(2)两种方法看似相同,很大不同。递归是倒推,大的不断往前得到小的。循环迭代是顺推,小的累积得到大的。