剑指Offer——跳台阶
题目描述
一只青蛙一次可以跳上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——跳台阶的更多相关文章
- (原)剑指offer跳台阶和矩形覆盖
跳台阶 时间限制:1秒空间限制:32768K 题目描述 一只青蛙一次可以跳上1级台阶,也可以跳上2级.求该青蛙跳上一个n级的台阶总共有多少种跳法. 分析同样为斐波那契数列边形这样的题肯定有公式 设 ...
- 剑指Offer 跳台阶
题目描述 一只青蛙一次可以跳上1级台阶,也可以跳上2级.求该青蛙跳上一个n级的台阶总共有多少种跳法. 解题思路: f(n)=f(n-1)+f(n-2); f(1)=1,f(2)=2; AC代码 ...
- 用js刷剑指offer(跳台阶)
题目描述 一只青蛙一次可以跳上1级台阶,也可以跳上2级.求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果). 牛客网链接 思路 这一题和斐波那契数列思路完全一样. 假如青蛙从第n个 ...
- 剑指offer--39. 跳台阶
时间限制:1秒 空间限制:32768K 热度指数:375795 题目描述 一只青蛙一次可以跳上1级台阶,也可以跳上2级.求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果). cla ...
- 剑指Offer-8.跳台阶(C++/Java)
题目: 一只青蛙一次可以跳上1级台阶,也可以跳上2级.求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果). 分析: 实际上就是斐波那契数列的一个应用,青蛙跳上n级台阶的跳法数等于跳 ...
- C#版 - 剑指offer 面试题9:斐波那契数列及其变形(跳台阶、矩形覆盖) 题解
面试题9:斐波那契数列及其变形(跳台阶.矩形覆盖) 提交网址: http://www.nowcoder.com/practice/c6c7742f5ba7442aada113136ddea0c3?tp ...
- 《剑指offer》 跳台阶
本题来自<剑指offer> 跳台阶 题目1: 一只青蛙一次可以跳上1级台阶,也可以跳上2级.求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果). 思路: 同上一篇. C ...
- 【Java】 剑指offer(9) 斐波那契数列及青蛙跳台阶问题
本文参考自<剑指offer>一书,代码采用Java语言. 更多:<剑指Offer>Java实现合集 题目 写一个函数,输入n,求斐波那契(Fibonacci)数列的第n项 ...
- 【剑指offer】09-2跳台阶,C++实现
原创博文,转载请注明出处! # 本文是牛客网<剑指offer>刷题笔记 1.题目 # 一只青蛙一次可以跳1级台阶,也可以跳2级.求该青蛙跳n级的台阶总共有多少种跳法. 2.思路 # 跳0级 ...
随机推荐
- 洛谷P2414 阿狸的打字机 [NOI2011] AC自动机+树状数组/线段树
正解:AC自动机+树状数组/线段树 解题报告: 传送门! 这道题,首先想到暴力思路还是不难的,首先看到y有那么多个,菜鸡如我还不怎么会可持久化之类的,那就直接排个序什么的然后按顺序做就好,这样听说有7 ...
- AndroidStudio自定义TODO
1.增加自定义TODO标记 Preferences -> Editor -> TODO,然后点击左下角的加号,输入想要自定义的TODO的正则 输入\bX\b.*(X为TODO标签的名字), ...
- kubernetes实战(二十五):kubeadm 安装 高可用 k8s v1.13.x
1.系统环境 使用kubeadm安装高可用k8s v.13.x较为简单,相比以往的版本省去了很多步骤. kubeadm安装高可用k8s v.11 和 v1.12 点我 主机信息 主机名 IP地址 说明 ...
- mongodb基础语法
Mongodb与关系型数据库最大的区别就是无约束, 既无字段(外键等)约束, 也没有数据类型约束, 以json存储 安装 启动Mongodb(默认在c盘找 data/db/文件夹) 服务端: mong ...
- SQL SERVER与ORACLE的几点区别
1.数据类型不同. sql server 的数据类型 int ,smallint ,char,varchar,nchar,nvarchar,ntext,datetime,smalldatet ...
- Shell初学(二)变量及数组
精简版: 定义:your_name=123 PS:=符号左右不能有空格! 使用:${your_name},单独使用变量时可以不加{} 只读:readonly your_name PS:设置 ...
- mysql 内置功能 存储过程 创建有参存储过程
对于存储过程,可以接收参数,其参数有三类: #in 仅用于传入参数用 #out 仅用于返回值用 #inout 既可以传入又可以当作返回值 传入参数使用格式 in 变量 数据类型 返回值使用格式 out ...
- 7 jmeter之参数化
badboy里参数化(前面4 jmeter badboy脚本开发技术详解已讲过) jmeter里参数化-1 用户参数 1.打开badboy工具,点击红色按钮开始录制,在地址栏目中输入地址:www.so ...
- [LeetCode] 230. Kth Smallest Element in a BST_Medium tag: Inorder Traversal
Given a binary search tree, write a function kthSmallest to find the kth smallest element in it. Not ...
- Q_UNUSED
Q_UNUSED() 没有实质性的作用,用来避免编译器警告 void func( int a) { Q_UNUSED(a); //函数体内没有使用a,避免编译器警告 }