(java题目第2讲)Fibonacci相关题目

来源:互联网 发布:时间服务器地址端口 编辑:程序博客网 时间:2024/05/10 07:40

古典问题:有一对兔子,从出生后第3个月起每个月都生一对兔子,小兔子长到第三个月后每个月又生一对兔子,假如兔子都不死,问每个月的兔子总数为多少?  

类似题目:一只青蛙一次上一个台阶或两个台阶,当上到n阶时有多少种方法?
//这是一个菲波拉契数列问题:输入序号n返回得到对应费波那西数

程序实现1——函数自迭代

 public int fnType1(int n)throws Exception{
  if(n==0){
   return 0;
  }else if(n==1||n==2){
   return 1;
  }else if(n>2){
   int temp=fnType1(n-1)+fnType1(n-2);


   if(temp<0){
    throw new Exception("Invalid value for int type, too larage");
   }else{
    return temp;
   }
  }else{
   throw new Exception("IllegalArgument value for n,please enter n>=0 ");
  }
 }

此种方式缺点:大量迭代不断消耗栈空间(搞web开发调试维护的都应该知道服务器栈资源的可贵,如果大量并发调用迭代导致服务器栈资源迟迟得不到回收,而导致web服务器崩溃),效率底,函数自闭性比较弱(优秀的接口应该对输入输出可能出现的错误信息进行捕捉,并提供清楚明了的处理结果),很容易出现错误,调试困难,实际应用中一般不建议使用这种方式,使用时迭代次数也不能超过3次;
程序实现2——时间换空间  :利用三个变量

 public int fnType2(int n){
  int result=-1;
  int temp1=0;
  int temp2=1;
  for(int index=0;index<=n;index++){

   if(index==0){
    result=temp1;

   }else if(index==1){
    result=temp2;

   }else{
    result=temp1+temp2;

    if(result<0){
     result=-2;
     break;
    }
    temp1=temp2;
    temp2=result;
   }
  }
  return result;
 }

此方法主要使用于:使用场景一:对于对象或变量使用次数比较少,使用一次以后就不会再使用的场景;使用场景二:对于内存资源比较稀缺的实时性要求不是太高的嵌入式系统设计中多会采用此种方式;
程序实现3——空间换取时间


 private static List<Integer> fnData=new ArrayList<Integer>();
 private static final int maxSize=50000;
 private static  void setFnData(){
  int result=-1;
  int temp1=0;
  int temp2=1;
  for(int index=0;index<=maxSize;index++){
   if(index==0){
    result=temp1;
   }else if(index==1){
    result=temp2;
   }else{
    result=temp1+temp2;
    if(result<0){
     result=-2;
     break;
    }
    temp1=temp2;
    temp2=result;
   }
   fnData.add(result);
  }
 }
 /**
  * 对外接口
  * @Title: getFnData
  * @Description: TODO
  * @param @param n
  * @param @return   
  * @return int <span style="font-family: sans-serif;">(n beyond fnData.size() and n<0 return -1)</span>
  * @throws
  */
 public int getFnData(int n){
  if(fnData.size()==0){
   setFnData();
  }
  if(fnData.size()>n&&n>=0){
   return fnData.get(n);
  }else{
   return -1;
  }
 }
此方法一般用于:对象或变量在程序运行的整个生命周期都存在或频繁调用的场景,如调用外部WebService接口、抽象持续化层、常用配置文件参数加载等等

黄金分割

规律表:

月数 小兔 中兔 老兔 总数
1 1 0 0 1
2 0 1 0 1
3 1 0 1 2
4 1 1 1 3
5 2 1 2 5
6 3 2 3 8
7 5 3 5 13

在计算每一行时,大兔数为上月的大兔数加上月的中兔数,中兔数为上月的小兔数,小兔数为本月的大兔数,算总数为本月的小兔数加本月的中兔数加本月的大兔数。在观察总数的过程中找出了规律:总数的第一、二月都是1,以后的每一月是前两月的和。数列为1,1,2,3,5,8,13,21,34,55,……

当n=50时,后项与前项的比是1.61803398874989,而前项与后项的比是0.61803398874989,即b/a的值与a/b的值相差1,假设后项与前项的比是φ,则有(φ-1)/φ=1,解这个方程得:φ= (√5+1) /2,这就是黄金分割。
当n充分大时,斐波纳契数列后前项的比值,与前后项的比值,相差1,它们的比值是黄金分割!黄金分割是一个十分有用的无理数。据此,把黄金分割可用一个有理数近似表示,如斐波纳契数列的第七项与斐波纳契数列的第六项的比13/8,斐波纳契数列的第九项与斐波纳契数列的第八项的比34/21等都可以近似地表示为黄金分割,当然项数越后越精确。

题目要求:编写程序在控制台输出斐波那契数列前20项,每输出5个数换行

方法一:publicclass Fibonacci1{

 //定义三个变量方法
 public static voidmain(String[] args) {
  int a=1, b=1, c=0;
  System.out.println("斐波那契数列前20项为:");
  System.out.print(a + "\t" + b +"\t");
  for (int i = 1; i<= 18; i++) {
   c = a +b;
   a = b;
   b = c;
   System.out.print(c+ "\t");
   if ((i + 2) %5 == 0) 
    System.out.println();  }}}

 

方法二:publicclass Fibonacci2{

 //定义数组方法
 public static void main(String[] args) {
  int arr[] = new int[20];
  arr[0] = arr[1] = 1;
  for (int i = 2; i< arr.length; i++) {
   arr[i] =arr[i - 1] + arr[i - 2]; }
  System.out.println("斐波那契数列的前20项如下所示:");
  for (int i = 0; i< arr.length; i++) {
   if (i % 5 ==0)

  System.out.println();   
   System.out.print(arr[i]+"\t"); }}}

 

方法三:publicclass Fibonacci3 {

 //使用递归方法
 private static int getFibo(int i) {
  if (i == 1 || i == 2)
  return 1;
  else
  return getFibo(i - 1) +getFibo(i - 2);}

 

 public static voidmain(String[] args) {
  System.out.println("斐波那契数列的前20项为:");
  for (int j = 1; j<= 20; j++) {
   System.out.print(getFibo(j)+ "\t");
   if (j % 5 ==0) 
    System.out.println();}}}



http://blog.csdn.net/zxq1138634642/article/details/8394223


http://www.jb51.net/article/45596.htm

http://blog.sina.com.cn/s/blog_85790123010155m8.html


最近做的一道题目:总结一下

关于输入一个数字n得到第n项斐波那契数列,求调用函数的次数:

#include <stdio.h>
int cnt=0;
int fib(int n){
cnt++;
if(n==0) 
return 1; 
else if(n==1) 
return 2; 
else 
return fib(n-1)+fib(n-2);
}
void main()
{
fib(8);
printf("%d",cnt);
}
分析如下:

fib(1)或者fib(0)调用次数都是1;fib(2)=fib(1)+fib(0),本身调用函数1次,加上fib(1)、fib(0)这两次,共3次;
fib(3)=fib(1)+fib(2),本身调用函数1次,加上fib(2)调用次数、fib(1)调用次数,共5(1+1+3)次;
fib(4)=fib(2)+fib(3),本身调用函数1次,加上fib(2)调用次数、fib(3)调用次数,共9(1+3+5)次;
fib(5)=fib(3)+fib(4),本身调用函数1次,加上fib(3)调用次数、fib(4)调用次数,共15(1+5+9)次;
fib(6)=fib(4)+fib(5),本身调用函数1次,加上fib(4)调用次数、fib(5)调用次数,共25(1+9+15)次;
fib(7)=fib(5)+fib(6),本身调用函数1次,加上fib(5)调用次数、fib(6)调用次数,共41(1+15+25)次;
fib(8)=fib(6)+fib(7),本身调用函数1次,加上fib(6)调用次数、fib(7)调用次数,共67(1+25+41)次;
所以,求第n位斐波那契数列的值时,调用函数的次数为 :1+(n-1)调用次数+(n-2)调用次数

0 0
原创粉丝点击