zoukankan      html  css  js  c++  java
  • 跳台阶问题/变态跳台阶,斐波拉契的四种解法

    取自牛客网,剑指Offer编程题

    一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果)。
    

      

    首先分析一下为啥是一个斐波拉契序列

    对于第N级阶梯,他的情况有下列两种:

    第一种是在n-2级的时候.跨两步到达n,此时有f(n-2)种跳法

    第二种是在n-1级的时候,跨一步到达n,此时有f(n-1)种跳法

    所以,第n级的跳法就有f(n-2)+f(n-1)种,很容易看来是斐波拉契了吧,虽然我第一眼看了很久不知道为啥是斐波拉契...

    对于变态跳台阶:

    他跟普通版的区别就是青蛙可以跳小于n的任意步,然后问题其实跟之前一样

    这里f(n)可以表示为f(n-1)+f(n-2)+......+f(n-n);

    f(n-1)可以表示为f(n-2)+f(n-3)+......+f(n-n);

    这样化解,就成了f(n) = 2 * f(n-1)

    这样,问题就迎刃而解了,做法就跟下面类似,就不赘述了

    再说解法

    第一:递归

    是最常见最普通同时也是最慢的方法了吧,因为这个过程中会产生大量的重复计算

    代码贴上来

    public static int Fibonacci(int n) {
            if(n==0)
                return 0;
            if(n==1)
                return 1;
            if (n==2)
                return 2;
            return Fibonacci(n-1)+Fibonacci(n-2);
        }
    

      

    我这里跑了530ms,太慢了,且看第二种

    第二种:存中间结果

    既然会产生重复计算,那么从这里出发,我们把中间计算过的都存起来,每次计算的时候只要取出来就行

    这样就能节省大量时间

    代码:

    import java.util.Arrays;
    public class Solution {
        private int[] temp = new int[1000];//存放中间结果的数组
        public Solution(){
            Arrays.fill(temp,-1);//所有元素初始化为-1
        }
        public int JumpFloor(int target) {
            if (target==0)
                return 0;
            if (target==1)
                return 1;
            if (target==2)
                return 2;
            if(temp[target]>0)
                return temp[target];//直接返回
            else
                temp[target] = JumpFloor(target-1)+JumpFloor(target-2);
            return temp[target];
        }
    }
    

      

    这段跑了22ms

    第三种:迭代,速度跟第二种差不多,稍微快一丢丢

    这里的思路就是计算的时候每次更新n-1和n-2级的跳法,也是避免重复计算

    import java.util.Arrays;
    public class Solution {
        public int JumpFloor(int target) {
            int[] n = {0,1,2};
            if (target<=2)
                return n[target];
            int pre = 1;//f(n-2)
            int in = 2;//f(n-1)
            int after = 0;//f(n)
            for (int i = 3;i<=target;i++){
                after = pre+in;
                pre = in;
                in = after;
            }
            return after;
        }
    }
    

      

    跑了20ms,比前面快一点

    听说还有一种矩阵快速幂,我还不是很会,待会研究研究

    好了,研究矩阵快速幂回来了

    首先总结一下学习快速幂

    首先,我们从指数出发,将指数转化而二进制,比如二的十次方,我们都知道答案是1024

    那么快速幂的思想就是,10转化为1010,那么就是0+2+0+8,按照幂来化简,就是2^0 * 2^2 * 2^0 * 2^8

    然后,1010是怎么来的,根据短除法就是10不停除二得到的,好了,快速幂的精髓地方就到了,我们不停除二得到了

    一些二进制的数字,说明白点就是取余吧,如果这个余数是0,那么我们就不用计算,但是底数还是照样累乘,然后没

    取余一次,因为要往后接着判断余数,所以b就缩小为以前的一半,然后,如果余数为1,就就与答案相乘

    不懂还是看代码吧,就明白了

     //快速幂
        public static long fastPower(int a,int b){
            long answer = 1;
            while (b>0){
                if(b%2==1)
                    answer = answer * a;
                b = b/2;
                a = a * a;
            }
            return answer;
        }
    

      

    这里b每次除二,所以最终计算的次数是肯定要小了很多了,如果指数很大,就更明显了

    然后转到矩阵快速幂,矩阵快速幂怎样跟斐波拉契联系起来呢,其实跟之前的快速幂相似,不过是以矩阵的形式

    可以参考下面的连接:https://www.cnblogs.com/ranjiewen/p/8998112.html

    定义一个初始矩阵int[][] base = {{1,1},{1,0}};单位矩阵int[][] answer = {{1,0},{0,1}};

    所以f(n) = base^(n-1)*answer[0][1]

    还是看代码吧,不难理解

     /*矩阵快速幂学习*/
        //2X2矩阵相乘
        public static int[][] Matrix(int[][] a,int[][] b){
            int[][] temp = {{0,0},{0,0}};
            for (int i = 0;i < 2;i++)
                for (int j = 0;j < 2;j++)
                    for (int k = 0;k < 2;k++)
                        temp[i][j] += a[i][k]*b[k][j];
            return temp;
        }
        //矩阵快速幂解斐波拉契
        public static int Fibonacci(int n){
            //初始化A
            int[][] base = {{1,1},{1,0}};
            //answer初始化为单位矩阵
            int[][] answer = {{1,0},{0,1}};
            while (n>0){
                if(n%2==1)
                    answer = Matrix(answer,base);
                base = Matrix(base,base);
                n = n /2;
            }
            return answer[0][0];
        }
    

      

  • 相关阅读:
    作业11图
    作业11
    作业10
    总结一
    物联网相关知识
    第十二次作业
    附加题4
    第十一次作业
    附加题3
    第十次作业
  • 原文地址:https://www.cnblogs.com/Yintianhao/p/10029235.html
Copyright © 2011-2022 走看看