栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

334、爬楼梯

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

334、爬楼梯

假设你正在爬楼梯。需要 n 阶你才能到达楼顶。

每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?

注意:给定 n 是一个正整数。

示例 1:

输入: 2
输出: 2
解释: 有两种方法可以爬到楼顶。
1. 1 阶 + 1 阶
2. 2 阶
示例 2:

输入: 3
输出: 3
解释: 有三种方法可以爬到楼顶。
1. 1 阶 + 1 阶 + 1 阶
2. 1 阶 + 2 阶
3. 2 阶 + 1 阶

来源:力扣(LeetCode)
链接:力扣
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

import java.util.HashMap;

import java.util.Map;

public class ClimbingStairs {

     

    

    public int climbStairs(int n) {

        if(n<=0) {

            return 0;

        }

        else if(n==1) {

            return 1;

        }else if(n==2) {

            return 2;

        }else {

            return climbStairs(n-1)+climbStairs(n-2);

        }

    }

     

    //看网友答案,递归时可以加点缓存。还以为可行,其实不行

    //因为是从后向前倒退的,因为前面几个没有计算,继续倒退

    //从小到大累加,才是更快的办法

    Map cache=new HashMap();

    public int climbStairsCache(int n) {

        if(n<=0) {

            return 0;

        }

        else if(n==1) {

            return 1;

        }else if(n==2) {

            return 2;

        }else {

            if(cache.get(n)!=null) {

                return cache.get(n);

            }

            int nValue= climbStairs(n-1)+climbStairs(n-2);

            cache.put(n, nValue);

            return nValue;

        }

    }

     

    

    public int climbStairsDp(int n) {

        if(n<=0) {

            return 0;

        }

        else if(n==1) {

            return 1;

        }else if(n==2) {

            return 2;

        }

        //0不用,感觉没有意义

        int[] array = new int[n+1];

        array[1]=1;

        array[2]=2;

        for(int index=3;index<=n;index++) {

            array[index]=array[index-1]+array[index-2];

        }

        return array[n];

    }

     

    

    public int climbStairsDpTmpVariable(int n) {

        if(n<=0) {

            return 0;

        }

        else if(n==1) {

            return 1;

        }else if(n==2) {

            return 2;

        }

        //0不用,感觉没有意义

        int dp1=1;

        int dp2=2;

        int dpIndex=0;

        for(int index=3;index<=n;index++) {

            //f(x)=f(x-1)+f(x-2)

            dpIndex=dp1+dp2;

            //向前滚动,复用变量

            dp1=dp2;

            dp2=dpIndex;

        }

        return dpIndex;

    }

     

    //方法4 矩阵快速幂,方法5 通项公式(纯数学了,艹)

}

package cn.fansunion.leecode;

import org.junit.Assert;

import org.junit.Test;

import cn.fansunion.leecode.todo.ClimbingStairs;

import cn.hutool.core.date.StopWatch;

public class ClimbingStairsTest {

    @Test

    public void test() {

        ClimbingStairs cs = new ClimbingStairs();

        final int actual45 = 1836311903;

        StopWatch sw45 = new StopWatch();

        sw45.start();

        Assert.assertEquals(cs.climbStairs(45), actual45);

        sw45.stop();

        System.out.println("45:"+sw45.getTotalTimeMillis()+"ms");

        StopWatch sw37 = new StopWatch();

        sw37.start();

        Assert.assertEquals(cs.climbStairs(37), 39088169);

        sw37.stop();

        System.out.println("37:"+sw37.getTotalTimeMillis()+"ms");

    }

     

    @Test

    public void testDp() {

        ClimbingStairs cs = new ClimbingStairs();

        final int actual45 = 1836311903;

        StopWatch sw45 = new StopWatch();

        sw45.start();

        Assert.assertEquals(cs.climbStairsDp(45), actual45);

        sw45.stop();

        System.out.println("45:"+sw45.getTotalTimeNanos()+"ns");

        StopWatch sw37 = new StopWatch();

        sw37.start();

        Assert.assertEquals(cs.climbStairsDp(37), 39088169);

        sw37.stop();

        System.out.println("37:"+sw37.getTotalTimeNanos()+"ns");

    }

     

    @Test

    public void climbStairsDpTmpVariable() {

        ClimbingStairs cs = new ClimbingStairs();

        final int actual45 = 1836311903;

        StopWatch sw45 = new StopWatch();

        sw45.start();

        Assert.assertEquals(cs.climbStairsDpTmpVariable(45), actual45);

        sw45.stop();

        System.out.println("45:"+sw45.getTotalTimeNanos()+"ns");

        StopWatch sw37 = new StopWatch();

        sw37.start();

        Assert.assertEquals(cs.climbStairsDpTmpVariable(37), 39088169);

        sw37.stop();

        System.out.println("37:"+sw37.getTotalTimeNanos()+"ns");

    }

     

    @Test

    public void testCache() {

        ClimbingStairs cs = new ClimbingStairs();

        final int actual45 = 1836311903;

        StopWatch sw45 = new StopWatch();

        sw45.start();

        Assert.assertEquals(cs.climbStairsCache(45), actual45);

        sw45.stop();

        System.out.println("45Cache:"+sw45.getTotalTimeMillis());

        StopWatch sw37 = new StopWatch();

        sw37.start();

        Assert.assertEquals(cs.climbStairsCache(37), 39088169);

        sw37.stop();

        System.out.println("37Cache:"+sw37.getTotalTimeMillis());

    }

}

总结
这里形成的数列正好是斐波那契数列,答案要求的 f(n)f(n) 即是斐波那契数列的第 nn 项(下标从 00 开始)。我们来总结一下斐波那契数列第 nn 项的求解方法:

nn 比较小的时候,可以直接使用过递归法求解,不做任何记忆化操作,时间复杂度是 O(2^n)O(2
n
),存在很多冗余计算。
一般情况下,我们使用「记忆化搜索」或者「迭代」的方法,实现这个转移方程,时间复杂度和空间复杂度都可以做到 O(n)O(n)。
为了优化空间复杂度,我们可以不用保存 f(x - 2)f(x−2) 之前的项,我们只用三个变量来维护 f(x)f(x)、f(x - 1)f(x−1) 和 f(x - 2)f(x−2),你可以理解成是把「滚动数组思想」应用在了动态规划中,也可以理解成是一种递推,这样把空间复杂度优化到了 O(1)O(1)。
随着 nn 的不断增大 O(n)O(n) 可能已经不能满足我们的需要了,我们可以用「矩阵快速幂」的方法把算法加速到 O(log n)O(logn)。
我们也可以把 nn 代入斐波那契数列的通项公式计算结果,但是如果我们用浮点数计算来实现,可能会产生精度误差。

作者:LeetCode-Solution
链接:力扣
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/704864.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号