题目描述

一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法。

思路分析

这个问题可以先从简单开始考虑,台阶只有1阶,只有1种跳法,台阶有2阶,有2种跳法:一种两次跳一级;另一种一次跳两级。然后考虑一般情况,当有n级台阶时,将f(n)作为总跳法,第1次跳的时候,可以有两种方法:一是跳一级,此时跳法数目等于后面剩下的n-1级台阶的跳法,即f(n-1);二是跳两级,此时跳法数目等于后面剩下的n-2级台阶的跳法。所以,n级台阶的跳法总数:f(n)=f(n-1)+f(n-2)。从这里可以看出,本题是斐波那契数列的一种变形。

但本题还有一种思路,就是将跳1级与跳2级看成排列组合问题,假设x为跳1级台阶的次数,y为跳2级台阶的次数,于是可知x+2y=n,即x=n-2y,这里可以看作对x与y的排列组合问题,即C(x+y,y)=C(n-y,y)。其中0<=y<=n/2。

代码实现

斐波那契数列实现

1、递归实现

相信很多人第一次接触到斐波那契数列的时候,就是使用递归实现,该实现简单直观,但该算法效率不高,因为递归会反复计算相同的子问题,随着n的增大,计算量也急剧增大,时间复杂度为T(n) = O(1.618 ^ n)。代码如下:

 public int recurFib(int n) {
if (n <= 0) {
return 0;
}
if (n == 1 || n == 2) {
return n;
}
return recurFib(n - 1) + recurFib(n - 2);
}

2、递推实现

使用递归实现的算法之所以效率太低,是因为重复计算太多,所以我们可以将中间结果保存,当再次计算的时候先查找一下。但有一种更简单的方法,就是从下向上计算,递归是从上到下计算,上面会依赖下面的值,因此会导致重复计算。我们使用从下往上计算,没有值依赖,算法复杂度就降为O(n)。首先根据f(1)和f(2)算出f(3),f(2)和f(3)算出f(4),以此类推即可算出f(n),实现代码如下:

  public int recursiveFib(int n) {
if (n <= 0) {
return 0;
}
if (n == 1 || n == 2) {
return n;
}
int fibN = 0;
int fibNMinusOne = 2;
int fibNMinusTwo = 1;
for (int i = 3; i <= n; i++) {
fibN = fibNMinusOne + fibNMinusTwo; fibNMinusTwo = fibNMinusOne;
fibNMinusOne = fibN;
}
return fibN;
}

3、矩阵法实现

还有一种矩阵法实现,算法效率最高,时间复杂度为O(logn),该算法是根据下面的公式:

上面的公式可以数学归纳法证明,感兴趣的可以自己搜索一下相关资料,有了上面的公式,就将求解f(n),转换成求二阶矩阵的n次方,然后取结果的第1行第2列即可。如果仅仅是矩阵的乘法,时间复杂度依旧为O(n),但可以使用快速幂的方法求解一个数的乘法。乘方的性质如下:

结合上面两个公式代码如下:

public class Solution {

    public int fib(int n) {
if (n <= 0) {
return 0;
}
if (n <= 2) {
return n;
}
int[][] unitMatrix = {{1, 1}, {1, 0}};
int[][] result = matrixPow(unitMatrix, n);
return result[0][0];
} public int[][] matrixPow(int[][] mat, int n) {
if (n == 1) {
return mat;
} else {
// n是偶数
if ((n & 1) == 0) {
int[][] temp = matrixPow(mat, n >> 1);
return matrixMultiply(temp, temp);
} else {
// n是奇数
int[][] temp = matrixPow(mat, (n - 1) >> 1);
return matrixMultiply(matrixMultiply(temp, temp), mat);
}
}
} /**
* 矩阵相乘
*
* @param m
* @param n
* @return 结果矩阵,m*n
*/
public int[][] matrixMultiply(int[][] m, int[][] n) {
int rows = m.length;
int cols = n[0].length;
int[][] r = new int[rows][cols]; for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
r[i][j] = 0;
for (int k = 0; k < m[i].length; k++) {
r[i][j] += m[i][k] * n[k][j];
}
}
}
return r;
} public static void main(String args[]) {
Solution s = new Solution();
int result = s.fib(3);
System.out.println(result);
}
}

排列组合实现

排列组合是将跳1级数目和跳2级数目看出一个组合,其中x为跳1级数目,y为跳2级数目,且x+2y=n,问题转换成从(x+y)个总跳数中选出y个跳2级的的组合,即C(x+y,y)=C(n-y,y)。实现代码如下:

public class Solution {

    public BigDecimal jiecheng(int number) {
BigDecimal result = new BigDecimal(1);
BigDecimal temp;
for (int i = number; i > 0; i--) {
temp = new BigDecimal(i);
result = result.multiply(temp);
}
return result;
} public int fib(int target) {
if (target <= 0) {
return 0;
}
BigDecimal result = new BigDecimal(0);
// the result is C(n-y,y)
for (int i = 0; i <= target / 2; i++) {
result = result.add(jiecheng(target - i).divide(jiecheng(target - 2 * i).multiply(jiecheng(i))));
}
return result.toBigInteger().intValue();
} public static void main(String args[]) {
Solution s = new Solution();
int result = s.fib(29);
System.out.println(result);
} }

剑指Offer——跳台阶的更多相关文章

  1. (原)剑指offer跳台阶和矩形覆盖

    跳台阶 时间限制:1秒空间限制:32768K 题目描述 一只青蛙一次可以跳上1级台阶,也可以跳上2级.求该青蛙跳上一个n级的台阶总共有多少种跳法.   分析同样为斐波那契数列边形这样的题肯定有公式 设 ...

  2. 剑指Offer 跳台阶

    题目描述 一只青蛙一次可以跳上1级台阶,也可以跳上2级.求该青蛙跳上一个n级的台阶总共有多少种跳法.   解题思路: f(n)=f(n-1)+f(n-2); f(1)=1,f(2)=2;   AC代码 ...

  3. 用js刷剑指offer(跳台阶)

    题目描述 一只青蛙一次可以跳上1级台阶,也可以跳上2级.求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果). 牛客网链接 思路 这一题和斐波那契数列思路完全一样. 假如青蛙从第n个 ...

  4. 剑指offer--39. 跳台阶

    时间限制:1秒 空间限制:32768K 热度指数:375795 题目描述 一只青蛙一次可以跳上1级台阶,也可以跳上2级.求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果). cla ...

  5. 剑指Offer-8.跳台阶(C++/Java)

    题目: 一只青蛙一次可以跳上1级台阶,也可以跳上2级.求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果). 分析: 实际上就是斐波那契数列的一个应用,青蛙跳上n级台阶的跳法数等于跳 ...

  6. C#版 - 剑指offer 面试题9:斐波那契数列及其变形(跳台阶、矩形覆盖) 题解

    面试题9:斐波那契数列及其变形(跳台阶.矩形覆盖) 提交网址: http://www.nowcoder.com/practice/c6c7742f5ba7442aada113136ddea0c3?tp ...

  7. 《剑指offer》 跳台阶

    本题来自<剑指offer> 跳台阶 题目1: 一只青蛙一次可以跳上1级台阶,也可以跳上2级.求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果). 思路: 同上一篇. C ...

  8. 【Java】 剑指offer(9) 斐波那契数列及青蛙跳台阶问题

     本文参考自<剑指offer>一书,代码采用Java语言. 更多:<剑指Offer>Java实现合集   题目 写一个函数,输入n,求斐波那契(Fibonacci)数列的第n项 ...

  9. 【剑指offer】09-2跳台阶,C++实现

    原创博文,转载请注明出处! # 本文是牛客网<剑指offer>刷题笔记 1.题目 # 一只青蛙一次可以跳1级台阶,也可以跳2级.求该青蛙跳n级的台阶总共有多少种跳法. 2.思路 # 跳0级 ...

随机推荐

  1. Nginx日志切割之Logrotate篇

    不管是什么日志文件,都是会越来越大的,大到一定程度就是个可怕的事情了,所以要及早的做处理,方法之一就是按时间段来存储,不过linux系统提供了Logrotate的日志管理工具,很好用,不用写计划任务脚 ...

  2. 2018/04/03 每日一个Linux命令 之 lastb/last

    今天还在想暴力破解一个服务器是怎么完成的....... -- lastb功能说明:列出登录系统失败的用户相关信息. -- 单独执行 lastb 时候,它会读取/var/log 下的 btmp 文件,输 ...

  3. my.cnf 详解

    [client] port =3306 socket =/tmp/mysql.sock [mysqld] port =3306 socket =/tmp/mysql.sock basedir =/us ...

  4. isScroll的滚动组件的用法

    <div class="wrapper">  <ul>     <li>1</li>     <li>2</li& ...

  5. crontab定时任务-干货案例

    自定义需求:实现消息队列. 1.创建一张mysql表结构 2.编写php脚本,便于sh文件执行 3.编写sh脚本,便于crontab定时执行 4.crontab -e 注册定时任务,如果此步不清楚请参 ...

  6. [py]django上线部署-uwsgi+nginx+py3/django1.10

    https://github.com/lannyMa/django-uwsgi-nginx.git 单机调试启动-确保项目代码没问题 - 克隆代码进入项目 git clone https://gith ...

  7. [py]处理文件的3个方法

    file处理的3个方法: f和f.readlines效果一样 # f.read() 所有行 -> 字符串 # f.readline 读取一行 -> 字符串 # f.readlines 所有 ...

  8. [LeetCode] 172. Factorial Trailing Zeroes_Easy tag: Math

    Given an integer n, return the number of trailing zeroes in n!. Example 1: Input: 3 Output: 0 Explan ...

  9. 摄影EV值深入研究

    1. 什么是EV值 1.1. EV值定义 EV(Exposure Value),曝光值,是反应曝光量的一个值.当感光度为ISO 100.光圈值为F1.曝光时间为1秒时,定义曝光量为0.曝光量减少一档时 ...

  10. thinkphp 隐藏表单验证原理

    function savetoken() //创建session('hash') ,然后在魔板中表单中加入隐藏域 getsession('hash'),提交表单验证值是否一样,如果一样验证通过,同时重 ...