算法筆記_001:斐波那契數的多種解法(Java)

本篇文章解決的問題來源於算法設計與分析課程的課堂做業,主要是運用多種方法來計算斐波那契數。具體問題及解法以下:html

1、問題1

問題描述:利用迭代算法尋找不超過編程環境可以支持的最大整數的斐波那契數是第幾個斐波那契數。(Java231-1 for int, 263-1 for longjava

解決方案:針對問題1,此處要使用迭代法來解決,具體實現代碼以下:算法

//用迭代法尋找編程環境支持的最大整數(int型)的斐波那契數是第幾個斐波那契數
    public static int max_int_iteration(){
        int a = 1,b = 1,c = 2;
        int count = 3;
        for( ;b < c; ){   //一旦c達到編程環境最大斐波那契數,便會產生內存溢出,從而變成一個負數,到此循環結束
            a = b;
            b = c;
            c = a + b;
            count++;
        }
        return count;
    }
    
    
    //用迭代法尋找編程環境支持的最大整數(long型)的斐波那契數是第幾個斐波那契數
    public static long max_long_iteration(){
        long a = 1,b = 1,c = 2;
        long count = 3;
        for( ;b<c; ){    //一旦c達到編程環境最大斐波那契數,便會產生內存溢出,從而變成一個負數,到此循環結束
            a = b;
            b = c;
            c = a + b;
            count++;
        }
        return count;
    }

 

2、問題2

問題描述:根據問題1計算的最大的斐波那契數序號n,採用遞歸方式計算第n個斐波那契數,看其是否能夠在3分鐘內完成。編程

解決方案:針對問題2,此處要使用遞歸法來解決,問題1實際運行結果爲:支持的最大整數(int型)值爲47,支持的最大整數(long型)值爲93。使用遞歸法計算第47個斐波那契數實際所需時間爲138秒左右(此處本人使用WIN7系統運行所得),具體實現代碼以下:數組

//遞歸法
    public static long recursion(long n){
        long result = 0;   //最後一個斐波那契數及存儲中間斐波那契數的變量
        if(n <= 0)
            result = 0;
        if(n == 1 || n == 2)
            result = 1;
        if(n > 2)
        {
            result = recursion(n-1) + recursion(n-2);
            //System.out.print(result+"  ");
        }
        return result;
    }
//具體實現就只需使用System.currentTimeMillis()方法獲取系統當前時間,就能夠你計算出計算第47個斐波那契數所需時間

 

3、問題3

問題描述:利用遞歸算法計算你的計算機可以在151050秒內計算出的最大斐波那契數是第幾個,利用迭代算法求解一樣的問題。ide

解決方案:針對問題3,此處先要了解得到系統當前時間的相關方法及用法,而後計算規定時間內計算出的最大斐波那契數就很簡單啦,具體實現代碼以下:post

//在1,5,10,50秒內使用迭代法算出的最大斐波那契數是第幾個
        public static void time_iteration(){
            int a = 1,b = 1,c = 2;
            long count = 3;
            long a1 = 0,a2 = 0,a3 = 0,a4 = 0;
            long t1 = System.currentTimeMillis(); 
            long t2 = System.currentTimeMillis();
            for( ;t2-t1 < 60000; ){   
                a = b;
                b = c;
                c = a + b;
                count++;
                t2 = System.currentTimeMillis(); 
                if(t2-t1 == 1000)
                    a1 = count;
                    //System.out.println("1秒內最大斐波那契數是第:"+count+"個 ");
                if(t2-t1 == 5000)
                    a2 = count;
                    //System.out.println("5秒內最大斐波那契數是第:"+count+"個 ");
                if(t2-t1 == 10000)
                    a3 = count;
                    //System.out.println("10秒內最大斐波那契數是第:"+count+"個 ");
                if(t2-t1 == 50000)
                    a4 = count;
                    //System.out.println("50秒內最大斐波那契數是第:"+count+"個 ");
            }
            System.out.println("迭代法1秒內最大斐波那契數是第:"+a1+"個 ");
            System.out.println("迭代法5秒內最大斐波那契數是第:"+a2+"個 ");
            System.out.println("迭代法10秒內最大斐波那契數是第:"+a3+"個 ");
            System.out.println("迭代法50秒內最大斐波那契數是第:"+a4+"個 ");
        }
    
    //遞歸法
    public static long recursion(long n){
        long result = 0;   //最後一個斐波那契數及存儲中間斐波那契數的變量
        if(n <= 0)
            result = 0;
        if(n == 1 || n == 2)
            result = 1;
        if(n > 2)
        {
            result = recursion(n-1) + recursion(n-2);
            //System.out.print(result+"  ");
        }
        return result;
    }
    
    //規定時間內,遞歸法計算出的最大斐波那契數是第幾個
    public static int recursion_time(long time){
        long starttime_dg=System.currentTimeMillis();
        int i=3;
        long endtime_dg=0;
        while(endtime_dg<starttime_dg+time*1000){
        endtime_dg=System.currentTimeMillis();
        i++;
        recursion(i);
        }
        return i;
        }
    
    //遞歸法在1,5,10,50秒內算出的最大斐波那契數是第幾個
    public static void fbnq_recursion_time(){
        
              System.out.println("1秒內最大斐波那契數是第:"+recursion_time(1)+"個 ");
          
              System.out.println("5秒內最大斐波那契數是第:"+recursion_time(5)+"個 ");
          
              System.out.println("10秒內最大斐波那契數是第:"+recursion_time(10)+"個 ");
          
              System.out.println("50秒內最大斐波那契數是第:"+recursion_time(50)+"個 ");
        
        
        }

 

4、問題4

問題描述:利用公式F(n) = [fn/sqrt(5)]快速計算第n個斐波那契數,找出出現偏差時的最小n值。其具體公式描述見下圖:測試

 

 

 

解決方案:針對問題4,只須要將上述公式用代碼來描述就能夠完成,具體實現代碼以下:url

//直接求值法(利用公式F(n) = [@n/sqrt(5)]快速計算第n個斐波那契數)
    public static double formula(int n){
        double result = 0;
        double temp = Math.sqrt(5.0);
        result =  (1/temp)*(Math.pow((1+temp)/2,n)-Math.pow((1-temp)/2, n));
        return result;
    }

 

5、問題5

問題描述:利用矩陣相乘方法計算第n個斐波那契數。spa

解決方案:對於矩陣相乘法,首先得對矩陣相乘的法則要熟悉,現簡單說明一下矩陣相乘求斐波那契數的思想及原理:

(1)矩陣定義

 

A
mxp 的矩陣,B
pxn 的矩陣,那麼稱
mxn
的矩陣C爲矩陣AB的乘積,記做
C =AB ,其中矩陣C中的第
i 行第
j 列元素能夠表示爲:
以下所示:
 

(2)矩陣相乘求斐波那契數原理
數列的遞推公式爲:f(1)=1,f(2)=1,f(3)=2 , f(n)=f(n-1)+f(n-2)(n>=3) 用矩陣表示爲:

  進一步,能夠得出直接推導公式:

具體實現代碼以下:

// 關聯矩陣  
    private static final int[][] UNIT = { { 1, 1 }, { 1, 0 } };   //定義一個上面公式中須要計算的二維數組
    // 全0矩陣  
    private static final int[][] ZERO = { { 0, 0 }, { 0, 0 } };  //定義一個元素均爲0的二維數組
    /** 
     * 求斐波那契數列 
     *  
     * @param n 
     * @return 
     */  
    public static int[][] fb(int n) {  
        if (n == 0) {  //指數n爲0時返回該數組
            return ZERO;  
        }  
        if (n == 1) {  //指數n爲1時返回該數組
            return UNIT;  
        }  
        // n是偶數  
        if ((n & 1) == 0) {  //把(n&1) == 0換成(n%2) == 0等價 , 惟一區別在於(n&1) == 0計算效率高 int[][] matrix = fb(n >> 1);  //n >> 1意思是指將n的二進制數向右移動1位,最高位補0。至關於把n除以2 return matrixMultiply(matrix, matrix);  
        }  
        // n是奇數  
        int[][] matrix = fb((n - 1) >> 1);  
        return matrixMultiply(matrixMultiply(matrix, matrix), UNIT);  
    }  
      
    /** 
     * 矩陣相乘 
     *  
     * @param m 
     *            r1*c1 
     * @param n 
     *            c1*c2 
     * @return 新矩陣,r1*c2 
     */  
    public static int[][] matrixMultiply(int[][] m, int[][] n) {  
        int rows = m.length;  
        int cols = n[0].length;  
        int[][] r = new int[rows][cols];  
        for (int i = 0; i < rows; i++) {  
            for (int j = 0; j < cols; j++) {  
                r[i][j] = 0;  
                for (int k = 0; k < m[i].length; k++) {  
                    r[i][j] += m[i][k] * n[k][j];  
                }  
            }  
        }  
        return r;  
    }  
    
    //具體實現矩陣相乘算法
    public static int matrix(int n){
        int[][] m = fb(n); 
        return m[0][1];
    }

 

6、問題6

問題描述:對於相同的輸入n值,比較上述四種方法的基本操做次數,以掌握對數、線性和指數增加率的極大差異。

解決方案:此處本人只是把上述所用的四種方法運行了一遍,計算各個相應方案計算第n個斐波那契數所花時間,由於具體算法相應的基本操做次數,用代碼來計算有點麻煩,因此此處就不羅列了。

 

7、新算法法

這是解決斐波那契數的一種新算法,該算法的時間和空間效率都優於上面四種算法,該算法所用公式以下圖所示:

 

具體實現代碼以下:

//新算法法
    public static int new_way(int n){
        //int a = 1,b = 1,c = 2,d = 3;
        int result = 0;   //定義最後一個斐波那契數
        //根據輸入n,求出最後一個斐波那契數
        if(n == 0)
            result = 0;
        else if(n == 1 || n == 2)
            result =  1;
        else if(n == 3)
            result =  2;
        else if(n >= 4){    //若n大於4返回resul
            int a1 = n/4;
            int b1 = n%4;
            int a = new_way(a1);
            int b = new_way((a1+1));
            int c = new_way((a1-1));
            int d = new_way((a1+2));
            if(b1 == 0)
                result = (int) ((Math.pow(b,2) - Math.pow(c,2))*(Math.pow(c, 2) + 2*Math.pow(a, 2) + Math.pow(b,2)));
            if(b1 == 1)
                result = (int) (Math.pow((Math.pow(b,2) - Math.pow(c,2)),2) + Math.pow((Math.pow(a, 2) + Math.pow(b,2)),2));
            if(b1 == 2)
                result = (int) ((Math.pow(a, 2) + Math.pow(b,2))*(3*Math.pow(b,2)+Math.pow(a, 2)-2*Math.pow(c,2)));
            if(b1 == 3)
                result = (int) (Math.pow((Math.pow(a, 2) + Math.pow(b,2)),2) + Math.pow((Math.pow(d,2)-Math.pow(a,2)),2));
        
        }
            return result;
    }

 

8、具體類運行實現

代碼以下:

  1 package com.liuzhen.ex_one;
  2 
  3 public class Fibonacci {
  4 
  5     //迭代法
  6     public static int iteration(int n){   /*此處(包含下面全部方法)聲明爲靜態方法,緣由是在本類main()方法中調用
  7         類中方法,對於通常的非static成員變量或方法,須要有一個對象的實例才能調用,因此要先生成對象的實例,他們纔會實際的分配內存空間。
  8         而對於static的對象或方法,在程序載入時便已經分配了內存空間,他只和特定的類想關聯,無需實例化  */
  9         int result = 1;  //最後一個斐波那契數
 10         int a[] = new int[n+1];    //存放斐波那契數,初始值爲空,默認全爲0
 11         a[0] = 0;
 12         a[1] = 1;
 13         //System.out.println("迭代法計算斐波那契數結果:");
 14         //System.out.print(a[0]+"  "+a[1]+"  ");
 15         for(int i = 2;i < n+1;i++){
 16             a[i] = a[i-1] + a[i-2];
 17             //result = a[i];
 18             //System.out.print(result+"  ");        //打印斐波那契數
 19         }
 20         //System.out.println();
 21         result=a[n];
 22         return result;    //返回最後一個斐波那契數
 23     }
 24     
 25     //用迭代法尋找編程環境支持的最大整數(int型)的斐波那契數是第幾個斐波那契數
 26     public static int max_int_iteration(){
 27         int a = 1,b = 1,c = 2;
 28         int count = 3;
 29         for( ;b < c; ){   //一旦c達到編程環境最大斐波那契數,便會產生內存溢出,從而變成一個負數,到此循環結束
 30             a = b;
 31             b = c;
 32             c = a + b;
 33             count++;
 34         }
 35         return count;
 36     }
 37     
 38     
 39     //用迭代法尋找編程環境支持的最大整數(long型)的斐波那契數是第幾個斐波那契數
 40     public static long max_long_iteration(){
 41         long a = 1,b = 1,c = 2;
 42         long count = 3;
 43         for( ;b<c; ){    //一旦c達到編程環境最大斐波那契數,便會產生內存溢出,從而變成一個負數,到此循環結束
 44             a = b;
 45             b = c;
 46             c = a + b;
 47             count++;
 48         }
 49         return count;
 50     }
 51     
 52     //在1,5,10,50秒內使用迭代法算出的最大斐波那契數是第幾個
 53         public static void time_iteration(){
 54             int a = 1,b = 1,c = 2;
 55             long count = 3;
 56             long a1 = 0,a2 = 0,a3 = 0,a4 = 0;
 57             long t1 = System.currentTimeMillis(); 
 58             long t2 = System.currentTimeMillis();
 59             for( ;t2-t1 < 60000; ){   
 60                 a = b;
 61                 b = c;
 62                 c = a + b;
 63                 count++;
 64                 t2 = System.currentTimeMillis(); 
 65                 if(t2-t1 == 1000)
 66                     a1 = count;
 67                     //System.out.println("1秒內最大斐波那契數是第:"+count+"個 ");
 68                 if(t2-t1 == 5000)
 69                     a2 = count;
 70                     //System.out.println("5秒內最大斐波那契數是第:"+count+"個 ");
 71                 if(t2-t1 == 10000)
 72                     a3 = count;
 73                     //System.out.println("10秒內最大斐波那契數是第:"+count+"個 ");
 74                 if(t2-t1 == 50000)
 75                     a4 = count;
 76                     //System.out.println("50秒內最大斐波那契數是第:"+count+"個 ");
 77             }
 78             System.out.println("迭代法1秒內最大斐波那契數是第:"+a1+"個 ");
 79             System.out.println("迭代法5秒內最大斐波那契數是第:"+a2+"個 ");
 80             System.out.println("迭代法10秒內最大斐波那契數是第:"+a3+"個 ");
 81             System.out.println("迭代法50秒內最大斐波那契數是第:"+a4+"個 ");
 82         }
 83     
 84     //遞歸法
 85     public static long recursion(long n){
 86         long result = 0;   //最後一個斐波那契數及存儲中間斐波那契數的變量
 87         if(n <= 0)
 88             result = 0;
 89         if(n == 1 || n == 2)
 90             result = 1;
 91         if(n > 2)
 92         {
 93             result = recursion(n-1) + recursion(n-2);
 94             //System.out.print(result+"  ");
 95         }
 96         return result;
 97     }
 98     
 99     //規定時間內,遞歸法計算出的最大斐波那契數是第幾個
100     public static int recursion_time(long time){
101         long starttime_dg=System.currentTimeMillis();
102         int i=3;
103         long endtime_dg=0;
104         while(endtime_dg<starttime_dg+time*1000){
105         endtime_dg=System.currentTimeMillis();
106         i++;
107         recursion(i);
108         }
109         return i;
110         }
111     
112     //遞歸法在1,5,10,50秒內算出的最大斐波那契數是第幾個
113     public static void fbnq_recursion_time(){
114         
115               System.out.println("1秒內最大斐波那契數是第:"+recursion_time(1)+"個 ");
116           
117               System.out.println("5秒內最大斐波那契數是第:"+recursion_time(5)+"個 ");
118           
119               System.out.println("10秒內最大斐波那契數是第:"+recursion_time(10)+"個 ");
120           
121               System.out.println("50秒內最大斐波那契數是第:"+recursion_time(50)+"個 ");
122         
123         
124         }
125     
126     //測試遞歸法在1,5,10,50秒內使用迭代法算出的最大斐波那契數是第幾個
127     public static void time_recursion_test(){
128         long t1 = System.currentTimeMillis(); 
129         long t2 = 0;
130         int i = 3;        
131         for(;t2-t1 > 60000;){
132             recursion(i);
133             i++;
134             t2 = System.currentTimeMillis();
135             if(t2-t1 == 1000)
136                 System.out.println("1秒內最大斐波那契數是第:"+i+"個 ");
137             if(t2-t1 == 5000)
138                 System.out.println("5秒內最大斐波那契數是第:"+i+"個 ");
139             if(t2-t1 == 10000)
140                 System.out.println("10秒內最大斐波那契數是第:"+i+"個 ");
141               if(t2-t1 == 50000)
142                 System.out.println("50秒內最大斐波那契數是第:"+i+"個 ");
143             
144         }
145     }
146     
147     //直接求值法(利用公式F(n) = [@n/sqrt(5)]快速計算第n個斐波那契數)
148     public static double formula(int n){
149         double result = 0;
150         double temp = Math.sqrt(5.0);
151         result =  (1/temp)*(Math.pow((1+temp)/2,n)-Math.pow((1-temp)/2, n));
152         return result;
153     }
154     
155     
156     //利用直接求值法,出現偏差時最小的n值
157     public static int min_formula(){
158         double result_fn=1;
159         int i=1;
160         while(result_fn-(double)iteration(i)<1){
161         result_fn=formula(i);
162         i++;
163         }
164         return i;
165     }
166     
167     //新算法法
168     public static int new_way(int n){
169         //int a = 1,b = 1,c = 2,d = 3;
170         int result = 0;   //定義最後一個斐波那契數
171         //根據輸入n,求出最後一個斐波那契數
172         if(n == 0)
173             result = 0;
174         else if(n == 1 || n == 2)
175             result =  1;
176         else if(n == 3)
177             result =  2;
178         else if(n >= 4){    //若n大於4返回resul
179             int a1 = n/4;
180             int b1 = n%4;
181             int a = new_way(a1);
182             int b = new_way((a1+1));
183             int c = new_way((a1-1));
184             int d = new_way((a1+2));
185             if(b1 == 0)
186                 result = (int) ((Math.pow(b,2) - Math.pow(c,2))*(Math.pow(c, 2) + 2*Math.pow(a, 2) + Math.pow(b,2)));
187             if(b1 == 1)
188                 result = (int) (Math.pow((Math.pow(b,2) - Math.pow(c,2)),2) + Math.pow((Math.pow(a, 2) + Math.pow(b,2)),2));
189             if(b1 == 2)
190                 result = (int) ((Math.pow(a, 2) + Math.pow(b,2))*(3*Math.pow(b,2)+Math.pow(a, 2)-2*Math.pow(c,2)));
191             if(b1 == 3)
192                 result = (int) (Math.pow((Math.pow(a, 2) + Math.pow(b,2)),2) + Math.pow((Math.pow(d,2)-Math.pow(a,2)),2));
193         
194         }
195             return result;
196     }
197     
198     
199     // 關聯矩陣  
200     private static final int[][] UNIT = { { 1, 1 }, { 1, 0 } };  
201     // 全0矩陣  
202     private static final int[][] ZERO = { { 0, 0 }, { 0, 0 } };  
203     /** 
204      * 求斐波那契數列 
205      *  
206      * @param n 
207      * @return 
208      */  
209     public static int[][] fb(int n) {  
210         if (n == 0) {  
211             return ZERO;  
212         }  
213         if (n == 1) {  
214             return UNIT;  
215         }  
216         // n是奇數  
217         if ((n & 1) == 0) {  
218             int[][] matrix = fb(n >> 1);  
219             return matrixMultiply(matrix, matrix);  
220         }  
221         // n是偶數  
222         int[][] matrix = fb((n - 1) >> 1);  
223         return matrixMultiply(matrixMultiply(matrix, matrix), UNIT);  
224     }  
225       
226     /** 
227      * 矩陣相乘 
228      *  
229      * @param m 
230      *            r1*c1 
231      * @param n 
232      *            c1*c2 
233      * @return 新矩陣,r1*c2 
234      */  
235     public static int[][] matrixMultiply(int[][] m, int[][] n) {  
236         int rows = m.length;  
237         int cols = n[0].length;  
238         int[][] r = new int[rows][cols];  
239         for (int i = 0; i < rows; i++) {  
240             for (int j = 0; j < cols; j++) {  
241                 r[i][j] = 0;  
242                 for (int k = 0; k < m[i].length; k++) {  
243                     r[i][j] += m[i][k] * n[k][j];  
244                 }  
245             }  
246         }  
247         return r;  
248     }  
249     
250     //具體實現矩陣相乘算法
251     public static int matrix(int n){
252         int[][] m = fb(n); 
253         return m[0][1];
254     }
255     
256     public static void main(String[] args){
257         System.out.print(max_int_iteration());
258         System.out.println();
259         System.out.print(max_long_iteration());
260         System.out.println();
261         System.out.println();
262         long t1 = System.currentTimeMillis();  
263         long a = recursion(47);
264         long t2 = System.currentTimeMillis();
265         System.out.println("遞歸法求斐波那契數:");
266         System.out.println(a);
267         System.out.println("遞歸算法Time is: " + (t2 - t1)/1000.0+"秒");
268         
269         //此處下面能夠直接經過給相關類傳遞參數,實現相應功能,上面的中代碼僅僅提供示例
270     }
271 
272 }
View Code

 

PS:運行部分結果截圖

 對於本問題,我本身用安卓作了一個簡單的展現界面(具體介紹請參考個人另外一篇博客用安卓實現斐波那契數和最近點對問題):

 

參考資料:

    一、斐波那契數列解析

    二、斐波那契數列的矩陣解法(java實現)

相關文章
相關標籤/搜索