取自牛客网,剑指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]; }