Fibonacci数列的解法:

 1、递归算法

 递归的概念,我说不清楚,语文不好。但是核心思想,我认为就是入栈出栈。比方说,你想要求得某个结果,如果一步求解不出来,那么先把最后一步的计算步骤进栈,先不考虑   它。转而去想,在求解最后一步之前的那一步应该怎么去做,就好比冬天穿衣服,再最后一步穿羽绒服之前我想大部分人会先穿一个羊毛衫(要是较真的话,内衣你应该会穿的吧)。这样,我们先把羽绒服放在一边(进栈),先去准备穿羊毛衫。然后,我们又发现在穿羊毛衫之前,我得穿个保暖内衣啊。好,我们再将羊毛衫先放一边(再进栈,此时羊毛衫在羽绒服上面放着)。这时候,我们穿上了保暖内衣,ok一下个——>栈的后入先出规则表示下一个我应该穿羊毛衫,ok穿上再下一个——>羽绒服。。。(下半身的穿衣流程类似,可能多一个胖次,自行脑补思考)。

 所以你看,现实当中很多时候的事情不是一下就可以完成的,而是需要一步一步的去完成,程序更是如此。你设计的代码,目的就是为了解决一个问题,在解决的过程中,会要进行很多的步骤,递归也是这样,只是它在解决问题之前一直在调用自身。

来看一下这个Fibonacci数列:

  Fibonacci数列的递推公式为:Fn=Fn-1+Fn-2,其中F1=F2=1。

  当n比较大时,Fn也非常大,现在我们想知道,Fn除以10007的余数是多少。

第一步,n是多少。按照题目意思,自己输入n。

第二步,怎么求,这里我假设有这么一个方法就叫做Fibonacci(int n),return一个int,将n传进去之后,经过这个方法后,我就得到了Fn。

第三步,分析一下,Fn=Fn-1+Fn-2=Fn-2+Fn-3+Fn-3+Fn-4=..........所以,要求Fn(羽绒服),先去求Fn-1和Fn-2(羊毛衫),要求Fn-1就要先去求Fn-2和Fn-3,以此类推,暂时      求不出来的,统统依次入栈,最后发现要求F3,我得先求F2和F1(F3入栈)。OK,F1=F2=1,F3就求出来了(F3出栈),又F4=F3+F2,F4也求得出来了(F4出栈).......之前入    栈的那些步骤,再依次出栈进行计算,直到Fn被求出来,计算Fn%10007本题结束。

第四步,放代码:

import java.util.Scanner;

public class Fibonacci {
//Fibonacci数列 递归算法
public static int Fibonacci (int n){
if(n==1||n==2){
return 1;
} else{
//操作入栈出栈的核心,递归调用
n = Fibonacci (n-1)+Fibonacci (n-2);
return n;
}
} public static void main(String[] args) {
while(true){
Scanner scanner = new Scanner(System.in);
int n;
n = scanner.nextInt();
int k = Fibonacci (n);
System.out.println(k%10007);
} } }

  

 2、整数求余

递归的算法虽然代码简洁,但是有一个比较不太好的地方,就是执行的效率很低,它是自身层层深入的调用,在时间和空间上的复杂度都很高,而且计算的重复性操作很多,在计算机内部还很有可能造成栈溢出的现象。比方说,用递归的方法计算N阶计算的时候,当N的值越来越大,很可能计算机就罢工了。

所以,本着递归和循环理论相同的原则,结合整数求余的规律,将代码改进如下:

import java.util.Scanner;

public class Fibonacci {
//Fibonacci数列 求余算法
public static int Fibonacci(int n){
int[] F = new int[n+1];//n+1是为了不让数组出现越界
F[1]=F[2]=1;
for(int i=3;i<=n;i++){
F[i] = (F[i-1] + F[i-2])%10007;
}
return F[n];
}
public static void main(String[] args) {
while(true){
Scanner scanner = new Scanner(System.in);
int n;
n = scanner.nextInt();
System.out.println(Fibonacci(n)); } } }

在方法里面定义一个长度为n+1的int型数组,用来存储数列的值,其中n+1是为了防止数组在执行过程当中产生越界的现象。然后,方法里面的核心在于整数求余的计算,即:

F[i] = (F[i-1] + F[i-2])%10007;

为什么这样写?当代码改进成这样时,我们就不需要先求得Fn的值再去取余数,而是直接在for循环中,直接就能将取余的运算执行,当循环结束。最后得到的Fn,就是数列中第N个数取余的结果。
为什么可以这样写?这里面是有整数取余运算的规律的,举个例子,1%10取余数就是1,2%10就是2,3%10就是3,那是不是3%10=1%10+2%10?再多举几个例子来进行验证:

5%10=5;10%10=0;15%10=5=5%10+10%10;
21%10=1;32%10=2;53%10=3=21%10+32%10;
57%7=1;89%7=5;146%7=6=57%7+89%7;
......
可以看到,好像的确是这样,这当中的原理,其实你思考一下是可以理解的,但是我说不太清楚,害怕误人子弟,想要深入理解,可以百度。
附加我找的一位前辈的博客链接,记录了取余运算规则:https://blog.csdn.net/ash_zheng/article/details/38541777
暂时就写到这了,欢迎评论交流,互相学习,哈哈。

Fibonacci数列的解法的更多相关文章

  1. 【编程题目】题目:定义 Fibonacci 数列 输入 n,用最快的方法求该数列的第 n 项。

    第 19 题(数组.递归):题目:定义 Fibonacci 数列如下:/ 0 n=0f(n)= 1 n=1/ f(n-1)+f(n-2) n=2输入 n,用最快的方法求该数列的第 n 项. 思路:递归 ...

  2. 青蛙跳台阶(Fibonacci数列)

    问题 一只青蛙一次可以跳上 1 级台阶,也可以跳上2 级.求该青蛙跳上一个n 级的台阶总共有多少种跳法. 思路 当n=1时,只有一种跳法,及f(1)=1,当n=2时,有两种跳法,及f(2)=2,当n= ...

  3. 程序员面试题精选100题(16)-O(logn)求Fibonacci数列[算法]

    作者:何海涛 出处:http://zhedahht.blog.163.com/ 题目:定义Fibonacci数列如下: /  0                      n=0 f(n)=      ...

  4. 【费式数列(Fibonacci数列)】

    /* 说明: Fibonacci为1200年代的欧洲数学家,在他的着作中曾经提到:若有一只兔子每个月生一只小兔子,一个月后也开 始生产.起初只有一只兔子,一个月后就有两只兔子,二个月后就有三只兔子,三 ...

  5. 常系数线性递推的第n项及前n项和 (Fibonacci数列,矩阵)

      (一)Fibonacci数列f[n]=f[n-1]+f[n-2],f[1]=f[2]=1的第n项的快速求法(不考虑高精度). 解法: 考虑1×2的矩阵[f[n-2],f[n-1]].根据fibon ...

  6. Fibonacci 数列算法分析

    /************************************************* * Fibonacci 数列算法分析 ****************************** ...

  7. 可变长度的Fibonacci数列

    原题目: Write a recursive program that extends the range of the Fibonacci sequence.  The Fibonacci sequ ...

  8. 入门训练 Fibonacci数列

      入门训练 Fibonacci数列   时间限制:1.0s   内存限制:256.0MB 问题描述 Fibonacci数列的递推公式为:Fn=Fn-1+Fn-2,其中F1=F2=1. 当n比较大时, ...

  9. fibonacci 数列及其应用

    fibonacci 数列及其延展 fibonacci计算 fibonacci数列是指 0,1,1,2,3,5,8,13,21……这样自然数序列,即从第3项开始满足f(n)=f(n-1)+f(n-2): ...

随机推荐

  1. Linux Android 多点触摸协议 原文出自【比特网】,转载请保留原文链接:http://soft.chinabyte.com/os/71/12306571.shtml

    为了使用功能强大的多点触控设备,就需要一种方案去上报用户层所需的详细的手指触摸数据.这个文档所描述的多点触控协议可以让内核驱动程序向用户层上报任意多指的数据信息. 使用说明 单点触摸信息是以ABS承载 ...

  2. Spring揭秘 读书笔记 五 容器的启动

    Spring的IoC容器所起的作用,就是生产bean,并维持bean间的依赖关系.它会以某种方式加载Configuration Metadata(通常也就是XML格式的配置信息),然后根据这些信息绑定 ...

  3. viewpager循环滚动和自动轮播的问题

    ViewPager是一个常用的android组件,不过通常我们使用ViewPager的时候不能实现左右无限循环滑动,在滑到边界的时候会看到一个不能翻页的动画,可能影响用户体验.此外,某些区域性的Vie ...

  4. Useful Articles for the Oracle E-Business Suite Technology Stack for Technical Consultant / DBA [ID

    Applies to:  Oracle Applications Technology Stack - Version: 11.5.10.2 to 12.1.3 - Release: 11.5.10 ...

  5. java工具类(四)之实现日期任意跳转

    Java实现日期任意跳转 项目开发过程中,需要进行订单提醒日期的设置,主要包括设置每月指定的日期或者指定的天数,代码如下: public static String DateOperation(Str ...

  6. Android开发中的安全

    根据Android四大框架来解说安全机制 代码安全 java不同于C/C++,java是解释性语言,存在代码被反编译的隐患: 默认混淆器为proguard,最新版本为4.7: proguard还可用来 ...

  7. Java 继承Thread类和实现Runnable接口的区别

    ava中线程的创建有两种方式: 1.  通过继承Thread类,重写Thread的run()方法,将线程运行的逻辑放在其中 2.  通过实现Runnable接口,实例化Thread类 在实际应用中,我 ...

  8. Linux下MySQL备份以及crontab定时备份

    1. 备份某个数据库 ################################################################## # 备份某个数据库 ############ ...

  9. 【linux学习笔记之一】linux系统目录结构以及常用系统命令

    序 ???这破笔记也要序?? 昨天开始学linux,做好笔记以备日后翻阅 Linux系统目录结构图 bin  --主要用于存放二进制文件(如:命令文件) boot--引导目录 dev  --设备目录 ...

  10. C语言之将无符号字符型转化为ascii码值

    这个宏是在linux内核中获取的,主要的功能是能够将一个无符号字符型的参数转化为ASCII码值. ASCII : ASCII 编码里包括了128个字符.用 十进制 0  到 127 来表示 .那就对了 ...