本文参考自《剑指offer》一书,代码采用Java语言。

更多:《剑指Offer》Java实现合集  

题目

  写一个函数,输入n,求斐波那契(Fibonacci)数列的第n项。

思路

  如果直接写递归函数,由于会出现很多重复计算,效率非常底,不采用。

  要避免重复计算,采用从下往上计算,可以把计算过了的保存起来,下次要计算时就不必重复计算了:先由f(0)和f(1)计算f(2),再由f(1)和f(2)计算f(3)……以此类推就行了,计算第n个时,只要保存第n-1和第n-2项就可以了。

测试用例

  1.功能测试(3,5,8等)

  2.边界值测试(0,1,2等)

  3.性能测试(50,100等)

  4.特殊(负数)

完整Java代码

(含测试代码)

/**
*
* @Description 斐波那契数列
*
* @author yongh
* @date 2018年9月13日 下午7:19:36
*/ // 题目:写一个函数,输入n,求斐波那契(Fibonacci)数列的第n项。 public class Fibonacci {
public long Fib(long n) {
if(n<0)
throw new RuntimeException("下标错误,应从0开始!");
if (n == 0)
return 0;
if (n == 1)
return 1;
long prePre = 0;
long pre = 1;
long result = 1;
for (long i = 2; i <= n; i++) {
result = prePre + pre;
prePre = pre;
pre = result;
}
return result;
} //附:缩略版(考虑到代码的可读性,其实还是上面的方法比较好)
public long Fib2(long n) {
if(n<0)
throw new RuntimeException("下标错误,应从0开始!");
if (n == 0)
return 0;
if (n == 1)
return 1;
long pre = 0;
long result = 1;
for (long i = 2; i <= n; i++) {
result += pre;
pre = result - pre;
}
return result;
} public static void main(String[] args) {
Fibonacci demo = new Fibonacci();
System.out.println(demo.Fib(0));
System.out.println(demo.Fib(1));
System.out.println(demo.Fib(2));
System.out.println(demo.Fib(8));
System.out.println(demo.Fib(50));
System.out.println(demo.Fib(100));
System.out.println(demo.Fib(-5));
}
}

  


Exception in thread "main" java.lang.RuntimeException: 下标错误,应从0开始!

Fibonacci

   时间复杂度:O(n)

拓展

时间复杂度为O(longn)的解法

  斐波那契数列有以下公式(可由数学归纳法推导得到):

  

  由上式可知,求f(n),只需要对矩阵求(n-1)次方即可,但此时时间复杂度仍为O(n)。利用乘方的性质

  利用递归的思路计算乘方,即可将时间复杂度降低为O(longn)。这里给出对乘方函数的递归代码(引用):

Matrix2By2 MatrixPower(unsigned int n)
{
assert(n > 0); Matrix2By2 matrix;
if(n == 1)
{
matrix = Matrix2By2(1, 1, 1, 0);
}
else if(n % 2 == 0)
{
matrix = MatrixPower(n / 2);
matrix = MatrixMultiply(matrix, matrix);
}
else if(n % 2 == 1)
{
matrix = MatrixPower((n - 1) / 2);
matrix = MatrixMultiply(matrix, matrix);
matrix = MatrixMultiply(matrix, Matrix2By2(1, 1, 1, 0));
} return matrix;
}

  

青蛙跳台阶问题

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

  将跳法总数记为f(n),可以知道f(1)=1,f(2)=2。当n>2时,第一次跳1级的话,还有f(n-1)种跳法;第一次跳2级的话,还有f(n-2)种跳法,所以可以推得f(n)=f(n-1)+f(n-2),即为斐波那契数列

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

  解法1:

  当n=1时,f(1)=1。

  当n大于1时,归纳总结可知:跳上n级台阶,第一次跳1级的话,有f(n-1)种方法;第一次跳2级的话,有f(n-2)种方法……第一次跳n-1级的话,有f(1)种方法;直接跳n级的话,有1种方法,所以可以得到如下公式:

  f(n) = f(n-1)+f(n-2)+......f(1)+1  (n≥2)

  f(n-1) = f(n-2)+f(n-3)+.....f(1)+1  (n>2)

  由上面两式相减可得,f(n)-f(n-1)=f(n-1),即f(n) = 2*f(n-1)  (n>2)

  最终结合f(1)和f(2),可以推得:f(n)=2^(n-1)

  解法2:

  假设跳到第n级总共需要k次,说明要在中间n-1级台阶中选出任意k-1个台阶,即C(n-1,k-1)种方法。

  所以:跳1次就跳上n级台阶,需要C(n-1,0)种方法;跳2次需要C(n-1,1)种方法……跳n次需要C(n-1,n-1)种方法

  总共需要跳C(n-1,0)+C(n-1,1)+C(n-1,2)+……C(n-1,n-1)=2^(n-1)种方法。

  解法3:

  除了必须到达最后一级台阶,第1级到第n-1级台阶都可以有选择的跳,也就是说对于这n-1个台阶来说,每个台阶都有跳上和不跳上2种情况,所以一共有2^(n-1)种方法。

矩形覆盖问题

 题目:用n个2*1的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法?

  当n = 1时,有一种方法。

  当n = 2时,有两种方法。

  当n >= 3时,和斐波那契数列类似。第一步竖着放,有f(n-1)种方法;第一步横着放,有f(n-2)种方法。所以f(n)=f(n-1)+f(n-2)。

收获

  1.求n次方时,可以利用递归来降低时间复杂度

  2.当遇到涉及n的问题时(类似青蛙跳台阶问题),不要紧张,可以进行归纳分析,特别注意f(n)与f(n-1)、f(n-2)等的关联,从而找出规律,进行合理建模。

  3.return (int)Math.pow(2,target-1);

    1) 转int类型

    2)pow不是power

更多:《剑指Offer》Java实现合集  

【Java】 剑指offer(9) 斐波那契数列及青蛙跳台阶问题的更多相关文章

  1. (1)剑指Offer之斐波那契数列问题和跳台阶问题

    一 斐波那契数列 题目描述: 大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项. n<=39 问题分析: 可以肯定的是这一题通过递归的方式是肯定能做出来,但是这样会有 ...

  2. 《剑指offer》斐波那契数列

    本题来自<剑指offer> 斐波那契数列 矩阵覆盖 题目一: 大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项(从0开始,第0项为0).n<=39 思路: ...

  3. 剑指offer:斐波那契数列

    目录 题目 解题思路 具体代码 题目 题目链接 剑指offer:斐波那契数列 题目描述 大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项(从0开始,第0项为0). n< ...

  4. 力扣 - 剑指 Offer 10- I. 斐波那契数列

    题目 剑指 Offer 10- I. 斐波那契数列 思路1(递归 / 自顶向下) 这题是很常见的一道入门递归题,可以采用自顶向下的递归方法,比如我们要求第n个位置的值,根据斐波那契数列的定义fib(n ...

  5. Go语言实现:【剑指offer】斐波那契数列

    该题目来源于牛客网<剑指offer>专题. 大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项(从0开始,第0项为0) n<=39 Go语言实现: 递归: ...

  6. 剑指offer三: 斐波拉契数列

    斐波拉契数列是指这样一个数列: F(1)=1; F(2)=1; F(n)=F(n-1)+F(n); public class Solution { public int Fibonacci(int n ...

  7. 剑指offer 07斐波那契数列

    现在要求输入一个整数n,请你输出斐波那契数列的第n项(从0开始,第0项为0).n<=39 java版本: public class Solution { public static void m ...

  8. 剑指Offer 7. 斐波那契数列 (递归)

    题目描述 大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项(从0开始,第0项为0). n<=39 题目地址 https://www.nowcoder.com/prac ...

  9. 《剑指offer》-斐波那契数列

    大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项. n<=39 这么直接的问fibonacci,显然是迭代计算.递归的问题在于重复计算,而迭代则避免了这一点:递归是自 ...

随机推荐

  1. C++内存管理(转)http://www.cnblogs.com/qiubole/archive/2008/03/07/1094770.html

    [导语] 内存管理是C++最令人切齿痛恨的问题,也是C++最有争议的问题,C++高手从中获得了更好的性能,更大的自由,C++菜鸟的收获则是一遍一遍的检查代码和对C++的痛恨,但内存管理在C++中无处不 ...

  2. 洛谷 P2257 YY的GCD

    洛谷 P2257 YY的GCD \(solution:\) 这道题完全跟[POI2007]ZAP-Queries (莫比乌斯反演+整除分块) 用的一个套路. 我们可以列出答案就是要我们求: \(ans ...

  3. BZOJ:1816 [Cqoi2010]扑克牌 (贪心或二分答案)

    题面 \(solution:\) 这道题难就难在你能否读懂题目的意思,我们将它翻译一下: 现在我有n根竹子(每根竹子有\(c_i\)节,每节竹子高度为1),我可以通过消耗一点法力值使某一根竹子的某两节 ...

  4. MHA-Failover可能遇到的坑

    一.主从数据一致性 1.1.如何保证主从数据一致性 参考叶师傅文章:FAQ系列 | 如何保证主从复制数据一致性 在MySQL中,一次事务提交后,需要写undo.写redo.写binlog,写数据文件等 ...

  5. Mybatis的分页插件PageHelper分页失效的原因

    引用博客:个人博客地址:https://alexaccele.github.io/ PageHelper是Mybatis的一个很好的分页插件,但要使用它的分页功能需要注意一下几点 1.导入相关包,例如 ...

  6. android view绘制流程 面试

    一.view树的绘制流程 measure--->layout--->draw measure 1.ViewGroup.LayoutParams 指定部件的长宽 2.MeasureSpec ...

  7. SpringBoot集成Spring Security(授权与认证)

    ⒈添加starter依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifact ...

  8. u盘的一些理解

    U盘是由主控板+FLASH+外壳组成的,当主控板焊接上空白FLASH后插入电脑,因为没有相应的数据,  量产工具 电脑只能识别到主控板,而无法识别到FLASH,所以这时候电脑上显示出U盘盘符,但是双击 ...

  9. linux统计某个特定文件名的大小总和【原创】

    [hch@EAISRVBJ2 log]$find ./ -name "test_chs_00*"|xargs du -ck|grep total|awk 'BEGIN{sum=0} ...

  10. 重装系统windows

    1 boot没有usb启动选项,驱动没加载好,先进入xp系统正确安装usb驱动,重启 2 file not fount bootmgr 用pe自带修复程序修复,修复驱动盘符为最小那个,非c盘 3 wi ...