JAVA基础-每次你可以爬1或2个台阶,爬到第n个台阶有多少种方法

33 阅读3分钟

介绍

这个问题被问到的或者说笔试中会遇到。但一般回答一两种就好,主要注意隐藏点,不要踩坑!问的不是有多少种方法,而是怎么样程序能实现输入和输出。

建议:面试回复第二种,第一种可作为对比!

重点:考虑性能!

题目描述:

    假设你正在爬楼梯。需要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];
}

如上代码中可以测试一下,对比递推就知道为何面试时候不建议说递归了!

第三种方法 通项公式

image.png

斐波那契数列的通项公式

包含着黄金分割数

用无理数表示有理数的典型案例

(缺点就是精度...。斐波那契数列是整数,公式得到的结果是实数)但整数部分相等。

不过基本上面试官也不会问到,写这种算法是因为可以和面试官说下,有把握的话能拿到高分

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);
}