1. 程式人生 > >Fibonacci數列問題

Fibonacci數列問題

IT 取余 int 第一步 思想 exti pre util 百度

 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數列問題