1. 程式人生 > >斐波那契數列3種解法(樸素遞迴、動態規劃、數學歸納)及演算法分析

斐波那契數列3種解法(樸素遞迴、動態規劃、數學歸納)及演算法分析

本文來自網易公開課的<演算法導論>第3講分治法。讓我對分治法的使用有了一個新的認識斐波那契數列,又稱黃金分割數列,F0=0,F1=1,Fn=F(n-1)+F(n-2)(n>=2,n∈N*)

下面我將使用Java(是的,又是Java,不過我覺得沒什麼問題,演算法嘛,重在思想)來分別實現這三種方法。後來視訊看到一半,發現使用樸素遞迴方法求解該問題時,有許多重複的子問題,那麼這就符合動態規劃的基本思想了,可以將採用自底向上的求解順序,儲存子問題的結果。這樣做的演算法時間是:theta(n)

1.樸素遞迴:自定向向下求解問題,導致了大量的重複求解

2.動態規劃:準確的講應該是一種自底向上的"動態規劃"思想解法。

3.數學歸納法(線性代數矩陣連乘公式)

設Fn表示第n個斐波那契數,那麼有定理:

證明:當n=1,F0=0,F1=1,F2=2,即:

那麼假設定理成立,將n-1帶入可得表示式:

即:

因為等式

恆成立,於是假設成立。

這樣就將斐波那契數列轉換成了n乘方問題了,那麼n乘方問題的演算法時間為什麼不是,而是呢?這裡可以使用分治法求解n乘方問題,可將n個數連乘分成左右相等的兩部分(偶數d的話n/2和n/2,奇數的話(n-1)/2和(n-1)/2)。就有:

這樣n個數連乘,只需劃分次即可。

程式碼如下:

package com.wly.algorithmproblem;

/**
 * 解斐波拉契數列問題,使用三種方法:樸素遞迴解法、自底向上的動態規劃思想解法、線性代數矩陣連乘公式解法
 * @author wly
 * @date 2013-11-28 
 *
 */
public class FibonacciSequence {
	
	private static int TESTCASE = 43;
	
	private static int[][] matrixUnit = {{1,1},{1,0}};
	
	public static void main(String[] args) {
		
		System.out.println("測試規模:" + TESTCASE);
		
		//---樸素遞迴解斐波那契數列問題測試
		long startT = System.currentTimeMillis();
		System.out.println("樸素遞迴:" + simpleRecurrence(TESTCASE));
		System.out.println("樸素遞迴用時:" + (System.currentTimeMillis()-startT));
		
		//---自底向上(動態規劃)解斐波那契數列問題測試
		startT = System.currentTimeMillis();
		System.out.println("自底向上(動態規劃):" + downToTopReslove(TESTCASE));
		System.out.println("自底向上(動態規劃)用時:" + (System.currentTimeMillis()-startT));
	
		//---線性代數矩陣解斐波那契數列問題測試
		int[][] mResult = {{1,1},{1,0}};
		startT = System.currentTimeMillis();
		int n = 1;
		while(n<TESTCASE) {
			mResult = matrixMutiple(mResult, matrixUnit);
			n ++;
		}
		System.out.println("線性代數矩陣公式:" + mResult[0][1]);
		System.out.println("線性代數矩陣公式用時:" + (System.currentTimeMillis()-startT));

		//分治法求m的n連乘測試
		System.out.println("分治法求2的23連乘:" + pow(2, 23));
	
		//兩矩陣相乘方法測試
		/*
		int[][] matrix1 = {{2,3,4},{1,2,3}};
		int[][] matrix2 = {{2,4},{3,5},{4,6}};
		int[][] result = new int[matrix1.length][matrix2[0].length];
		int[][] resultS = matrixMutiple(matrix1,matrix2,result);
		System.out.println();
		*/
		
	}
	
	
	/**
	 * 樸素遞迴
	 * @param n 
	 * @return 第n個斐波那契數
	 */
	public static int simpleRecurrence(int n) {
		if(n == 0) {
			return 0;
		} 
		if(n == 1 || n == 2) {
			return 1;
		}
		
		return simpleRecurrence(n-1) + simpleRecurrence(n-2);
	}
	
	/**
	 * 自底向上包含"動態規劃"思想的解法
	 * @param n
	 * @return 第n個斐波那契數
	 */
	public static int downToTopReslove(int n) {
		if(n == 0) {
			return 0;
		} else if(n == 1 || n == 2) {
			return 1;
		} else {
			int[] fibonacciArray = new int[n+1]; //fibonacciArray[i]表示第i個斐波那契數
			fibonacciArray[0] = 0;
			fibonacciArray[1] = 1;
			fibonacciArray[2] = 1;
			for(int i=3;i<=n;i++) { //注意由於fibonacciArray[0]表示第0個元素,這裡是i<=n,而不是i<n
				fibonacciArray[i] = fibonacciArray[i-1] + fibonacciArray[i-2];
			}
			
			return fibonacciArray[fibonacciArray.length-1];
		}
	}
	
	
	/**
	 * 分治法求解factor的n次方
	 * @param factor 基數
	 * @param n 次方數
	 * @return
	 */
	public static long pow(long factor,int n) {
		if(n == 0) {
			return 1;
		} else if(n == 1){
			return factor;
		} else {
			if(n % 2 == 1) { //乘法數為奇數
				return pow(factor,(n-1)/2) * pow(factor, (n-1)/2) * factor;
			} else { //乘方數為偶數
				return pow(factor, n/2) * pow(factor, n/2);
			}
		}
	}
	
	/**
	 * 兩矩陣相乘
	 * @param matrix1
	 * @param matrix2
	 * @return
	 */	
	public static int[][] matrixMutiple(int[][] matrix1,int[][] matrix2) {
		int[][] result = new int[matrix1.length][matrix2[0].length];
		for(int i=0;i<matrix1.length;i++) {
			for(int j=0;j<matrix2[i].length;j++) {
				int temp = 0;
				for(int k=0;k<matrix1[0].length;k++) {
					temp = matrix1[i][k] * matrix2[k][j] + temp;
				}
				result[i][j] = temp;
			}
		}
		return result;
	}
}
執行結果:
測試規模:43
樸素遞迴:433494437
樸素遞迴用時:1669
自底向上(動態規劃):433494437
自底向上(動態規劃)用時:0
線性代數矩陣公式:433494437
線性代數矩陣公式用時:1
分治法求2的23連乘:8388608

這裡有一點需要說明的是,程式碼中已經包含了m的n次方的程式碼。本來想講它結合到第三種線性代數矩陣連乘的解法中的,但是後來發現那樣的話,程式碼顯得很亂,於是就只是簡單的使用while來連乘了n次實現。總的來說還是實現了三種不同的解斐波拉契數列的方法,希望能夠大家一點參考

O啦~~~

轉載請保留出處:

謝謝!!

相關推薦

數列3解法(樸素動態規劃數學歸納)演算法分析

本文來自網易公開課的<演算法導論>第3講分治法。讓我對分治法的使用有了一個新的認識斐波那契數列,又稱黃金分割數列,F0=0,F1=1,Fn=F(n-1)+F(n-2)(n>=2,n∈N*) 下面我將使用Java(是的,又是Java,不過我覺得沒什麼問題,演

數列(一)--對比動態規劃(JAVA)

兔子繁殖問題: 這是一個有趣的古典數學問題,著名義大利數學家Fibonacci曾提出一個問題:有一對小兔子,從出生後第3個月起每個月都生一對兔子。小兔子長到第3個月後每個月又生一對兔子。按此規律,假設沒有兔子死亡,第一個月有一對剛出生的小兔子,問第n個月有多少

數列解法

數列:1,1,2,3,5,8,13,21,34,55…….,被稱為斐波那契數列。 斐波那契數列特點:第一、第二個數為1,從第三個數開始,該值等於其前面兩個數之和。 本文主要解決計算第N個斐波那契數的值。 1. 遞迴 /** * 斐波那契數列

數列的python實現(與list實現)

斐波那契數列概念 斐波那契數列(Fibonacci sequence),又稱黃金分割數列、因數學家列昂納多·斐波那契(Leonardoda Fibonacci)以兔子繁殖為例子而引入,故又稱為“兔子數列”,指的是這樣一個數列:1、1、2、3、5、8、13、21、34、……

Python學習--數列--迭代法和法實現

斐波那契數列實現的兩種方式 迭代法: 使用迭代法速度快,運算幾乎不用等待,例如計算99代,可以瞬間出答案,效率比遞迴法快,但是程式冗雜。 def fib(n): n1 = 1 n2 = 1 n3 = 1 if n < 1:

python實現數列:迭代和對比

迭代和遞迴 從概念上講,遞迴就是指程式呼叫自身的程式設計思想,即一個函式呼叫本身;迭代是利用已知的變數值,根據遞推公式不斷演進得到變數新值得程式設計思想。 對於剛入門的程式設計小白而言,對遞迴的理解應該是要難於對迭代的理解的。下面將以python實現斐波那契

數列的矩陣解法(java實現)

使用了二分法 import java.util.Scanner; /** * 求斐波那契數列<br/> * <pre> * [F(n+1) F(n)] [1 1 ]^n (n次方,可以使用歸納法證明)<br/> *

數列演算法的時間複雜度

斐波那契數列簡介: 斐波那契數列(Fibonacci sequence),又稱黃金分割數列、因數學家列昂納多·斐波那契(Leonardoda Fibonacci)以兔子繁殖為例子而引入,故又稱為“兔子數列”,指的是這樣一個數列:1、1、2、3、5、8、13、21、34、……

數列面試題解法(java)

斐波那契數列經常出現在程式設計師面試的題目中,本文總結一下斐波那契數列的解法 斐波那契數列(Fibonacci sequence),又稱黃金分割數列、因數學家列昂納多·斐波那契(Leonardoda Fibonacci)以兔子繁殖為例子而引入,故又稱為“兔子數

【矩陣乘法x2】LuoGu P1349 廣義數列&&LNSYOJ#395推式字首和

這是兩道矩陣的水題 題目描述 數列f[n]=f[n-1]+f[n-2]+n+1,f[1]=f[2]=1的前n項和s[n]=f[1]+f[2]+……+f[n]的快速求法(答案取模10e9+7) 輸入格式 一個整數bb。 輸出格式 一個整數字首和。

數列的三解法時間複雜度

斐波那契數列: f(n)=f(n-1)+f(n-2)(n>2) f(0)=1;f(1)=1; 即有名的兔子繁衍問題 在本篇文章我將會給出三種解法

數列,1 2 3 5 8......兩方式(JavaScript)

序列:1,2,3,5,8,13...。找出第20個數是多少?得出前20個數之和是多少? 方法一:            var i=1, j=1,sum=0;            for(var k=0;k<20;k++){                    

3方法求解數列

Fibonacci Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 7241 Accepted: 5131 Description In the Fibonacci integer sequence, F0 = 0, F

數列的幾計算機解法

斐波那契數列傳說起源於一對非常會生的兔子。定義: 這個數列有很多奇妙的性質(比如 F(n+1)/F(n) 的極限是黃金分割率),用計算機有效地求解這個問題的解是一個比較有意思的問題,本文一共提供了4種解法。 解法一:遞迴 這是最最最直觀的想法,是每個人都能編寫

數列歸和非解法

err nbsp div clas pan 斐波那契 ret ror ++ //遞歸解法 function fib(n){ if(n < 1){ throw new Error(‘invalid arguments‘); }

數列的兩實現(歸和非歸)

result 數列 == 非遞歸 fib color 效率 i++ 思想 查找斐波納契數列中第 N 個數。 所謂的斐波納契數列是指: 前2個數是 0 和 1 。 第 i 個數是第 i-1 個數和第i-2 個數的和。 斐波納契數列的前10個數字是: 0, 1, 1, 2,

方法數列

times ret Coding value self. utf-8 () 數列 fib __author__ = ‘hechangting‘ #ecoding=utf-8 import itertools #叠代器 class Fib: def __init__

數列,1.1.2.3.5.8......,輸入一個數字,比如3,顯示前面三個數字1,1,2.

int 都是 AR public 運行 sca ... 3.5 info 斐波那契數列(從第三個數字開始都是前面兩個數字的和),1.1.2.3.5.8......,輸入一個數字,比如3,顯示前面三個數字1,1,2. 1 public class practice {

C語言經典演算法(八)——實現數列的兩方法

後繼續整理演算法並寫出自己的理解和備註。 C++實現的:遞迴實現斐波那契數列 1、 遞迴實現斐波那契數列Fib(n) <1> 題目描述:輸入n值,求解第n項的斐波那契數列值 <2> 方法一:概念法 <3> 方法二:遞迴法 斐波那契數列值是值1

數列的幾變體

斐波那契數列的本源形式:          f(0) = 0; f(1) = 1; f(n) = f(n-1) + f(n-2). 斐波那契數列的程式碼實現: (1)迴圈: public int