介绍
这个问题被问到的或者说笔试中会遇到。但一般回答一两种就好,主要注意隐藏点,不要踩坑!问的不是有多少种方法,而是怎么样程序能实现输入和输出。
建议:面试回复第二种,第一种可作为对比!
重点:考虑性能!
题目描述:
假设你正在爬楼梯。需要N阶你才能达到楼顶
每次你可以爬1个或者2个台阶。问你有多少种不同方法可以爬到楼顶
思路分析
这个题目其实是一个简单的递推问题,其实就是一个斐波那契数列。
想一下,第n个台阶可以从第一节爬上来?只能是n-1和n-2啊,所以我们就能得到递推公式
f(n)=f(n-1)+f(n-2),f(n)表示到n阶台阶的方法数,看公式这就是典型的斐波那契数列
第一种方法 递归(建议不要回答这种,除非想不起来其他)
递归的出口是当n=1时候值为1,当n=2时候值为2
public static void main(String[] args) {
System.out.println("开始时间:"+System.currentTimeMillis());
System.out.println("递归求出第n阶台阶有多少种抵达方法"+recursion(50));
System.out.println("结束时间:"+System.currentTimeMillis());
}
/**
* 递归求出第n阶台阶有多少种抵达方法
* @param n
* @return
*/
public static long recursion(long n) {
if(n==1 || n==2){
return n;
}
return recursion(n-1) + recursion(n-2);
}
为何说不建议回答面试官或者笔试中写这种方法。递归耗时且耗内存。如果真有业务代码中你去写个递归,可以想象一下结果!
如上代码中可以测试一下,n=50?基本上就需要耗时30秒左右......
所以面试回答时候可以说一下这个方法,但是一定要说出他的劣势,以及准备其他方案。笔试中非必要千万不要写这种
第二种方法 递推
一般回答这种方式即可,时间复杂度为O(n)
当n=1时候值为1,当n=2时候值为2
当n>=3的递推公式是fn)=f(n-1)+f(n-2)
public static void main(String[] args) {
System.out.println("开始时间:"+System.currentTimeMillis());
System.out.println("递推求出第n阶台阶有多少种抵达方法"+recursive(500));
System.out.println("结束时间:"+System.currentTimeMillis());
}
/**
* 递推求出第n阶台阶有多少种抵达方法
*/
public static long recursive(long n) {
if(n==1 || n==2){
return n;
}
long[] f=new long[(int) (n+1)];
f[1]=1;
f[2]=2;
for (int i = 3; i <=n; i++) {
f[i]=f[i-1]+f[i-2];
}
return f[(int) n];
}
如上代码中可以测试一下,对比递推就知道为何面试时候不建议说递归了!
第三种方法 通项公式
斐波那契数列的通项公式
包含着黄金分割数
用无理数表示有理数的典型案例
(缺点就是精度...。斐波那契数列是整数,公式得到的结果是实数)但整数部分相等。
不过基本上面试官也不会问到,写这种算法是因为可以和面试官说下,有把握的话能拿到高分
public static void main(String[] args) {
System.out.println("开始时间:"+System.currentTimeMillis());
System.out.println("求出第n阶台阶有多少种抵达方法"+formula(100));
System.out.println("结束时间:"+System.currentTimeMillis());
}
/**
* 通项公式
*/
public static long formula(long n) {
double sqrt5 = Math.sqrt(5);
double fibn = Math.pow((1 + sqrt5) / 2, n + 1) - Math.pow((1 - sqrt5) / 2, n + 1);
return (long) (fibn / sqrt5);
}