Fibonacci数列的解法
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数列的解法的更多相关文章
- 【编程题目】题目:定义 Fibonacci 数列 输入 n,用最快的方法求该数列的第 n 项。
第 19 题(数组.递归):题目:定义 Fibonacci 数列如下:/ 0 n=0f(n)= 1 n=1/ f(n-1)+f(n-2) n=2输入 n,用最快的方法求该数列的第 n 项. 思路:递归 ...
- 青蛙跳台阶(Fibonacci数列)
问题 一只青蛙一次可以跳上 1 级台阶,也可以跳上2 级.求该青蛙跳上一个n 级的台阶总共有多少种跳法. 思路 当n=1时,只有一种跳法,及f(1)=1,当n=2时,有两种跳法,及f(2)=2,当n= ...
- 程序员面试题精选100题(16)-O(logn)求Fibonacci数列[算法]
作者:何海涛 出处:http://zhedahht.blog.163.com/ 题目:定义Fibonacci数列如下: / 0 n=0 f(n)= ...
- 【费式数列(Fibonacci数列)】
/* 说明: Fibonacci为1200年代的欧洲数学家,在他的着作中曾经提到:若有一只兔子每个月生一只小兔子,一个月后也开 始生产.起初只有一只兔子,一个月后就有两只兔子,二个月后就有三只兔子,三 ...
- 常系数线性递推的第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 ...
- Fibonacci 数列算法分析
/************************************************* * Fibonacci 数列算法分析 ****************************** ...
- 可变长度的Fibonacci数列
原题目: Write a recursive program that extends the range of the Fibonacci sequence. The Fibonacci sequ ...
- 入门训练 Fibonacci数列
入门训练 Fibonacci数列 时间限制:1.0s 内存限制:256.0MB 问题描述 Fibonacci数列的递推公式为:Fn=Fn-1+Fn-2,其中F1=F2=1. 当n比较大时, ...
- fibonacci 数列及其应用
fibonacci 数列及其延展 fibonacci计算 fibonacci数列是指 0,1,1,2,3,5,8,13,21……这样自然数序列,即从第3项开始满足f(n)=f(n-1)+f(n-2): ...
随机推荐
- html详解(二)
4.多媒体标签 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www ...
- 开源视频平台:ViMP
ViMP是一个开源的视频平台,可以用于建立自己的视频门户.可以用于VoD系统,网络学习系统,企业内部视频系统的搭建. 这一阵子一直在研究网络视频平台.发现这类的开源系统相对来说还是比较少的,因此在发现 ...
- 漫谈程序员(十八)windows中的命令subst
漫谈程序员(十八)windows中的命令subst 用法格式 一.subst [盘符] [路径] 将指定的路径替代盘符,该路径将作为驱动器使用 二.subst /d 解除替代 三.不加任何参数键入 ...
- android 数据重构(仿淘宝浏览记录,足迹)
数据结构 ->数据重构 原因 处理这个数据的主要原因是,后台服务器返回的数据格式在ios那边因为其控件可以对数据进行分区显示,可以直接处理,而在android上我们显示控件就是listview, ...
- web容器的会话机制
基本所有web应用开发的朋友都很熟悉session会话这个概念,在某个特定时间内,我们说可以在一个会话中存储某些状态,需要的时候又可以把状态取出来,这整个过程的时间空间可以抽象成"会话&qu ...
- LeetCode之“链表”:Sort List
题目链接 题目要求: Sort a linked list in O(n log n) time using constant space complexity. 满足O(n log n)时间复杂度的 ...
- LeetCode之“链表”:Remove Nth Node From End of List
题目链接 题目要求: Given a linked list, remove the nth node from the end of list and return its head. For ex ...
- 【Visual C++】游戏编程学习笔记之五:单一背景滚动
本系列文章由@二货梦想家张程 所写,转载请注明出处. 本文章链接:http://blog.csdn.net/terence1212/article/details/44224963 作者:ZeeCod ...
- OAF中的TableLayout 高级表格
我们经常会遇到这种情况,我们要把显示界面分成几块区域来分别显示不同的内容.比如在同一行左边显示messageComponentLayout,右边显示table,这时,我们就要用到tableLayout ...
- didLoadFromCCB方法的调用顺序
该方法运行顺序和其(包含)继承体系顺序的逆序相同. 这意味着孩子的didLoadFromCCB将总是在其父的didLoadFromCCB之前调用. 比如GameScene.ccb中含有GameMenu ...