31-3(关于斐波那契数的三个算法) 在已知n的情况下,本题对计算第n个斐波那契数Fn的三种算法的效率进行了比较。假定两个数的加法,减法和乘法的代价都是O(1),与数的大小无关。
a.证明:基于递归式(3.22)计算Fn的直接递归方法的运行时间为n的幂。
b.试说明如何运用记忆法在O(n)时间内计算Fn.
c.试说明如何仅用整数加法和乘法运算,就可以在O(lgn)的时间内计算Fn.(提示:考虑2x2矩阵[0,1,1,1]和它的幂。)
3.22: Fibonacci numbers
We define the Fibonacci numbers by the following recurrence:
F(0) = 0, F(1) = 1, F(i) = F(i-1) + F(i-2) for (i>=2).
/* 31-3 Three algorithms for Fibonacci numbers 3.22
3.22: Fibonacci numbers
We define the Fibonacci numbers by the following recurrence:
F(0) = 0, F(1) = 1, F(i) = F(i-1) + F(i-2) for (i>=2).
*/
public class FibonacciNumbers {
public static void main(String[] args) {
for(int i=0; i< 20; i++) {
System.out.println("fibona("+i+")="+fibona1(i));
}
for(int i=0; i< 20; i++) {
System.out.println("fibona("+i+")="+fibonaByMatrixPower(i+1).getFibonaNb());
}
for(int i=0; i< 20; i++) {
System.out.println("fibona("+i+")="+fibona2(i));
}
}
// b. Show how to compute F(n) in O(n) time using memoization O(n) space.
public static int fibona2(int n) {
if(n<0) throw new IllegalArgumentException("Fibonacci(n), n>=0");
if(n == 0 || n == 1) {
return n;
}
int[] result = new int[n+1];
result[0] = 0;
result[1] = 1;
for(int i=2; i<=n; i++) {
result[i] = result[i-1] + result[i-2];
}
return result[n];
}
// b. Show how to compute F(n) in O(n) time using O(1) space.
public static int fibona1(int n) {
if(n<0) throw new IllegalArgumentException("Fibonacci(n), n>=0");
if(n==0) return 0; // f(0) = 0;
if(n==1) return 1;
if(n==2) return 1;
int fn_1 = 1;
int fn_2 = 1;
int fn = 0;
for(int i=3; i<=n; i++) {
fn = fn_1 + fn_2;
fn_2 = fn_1;
fn_1 = fn;
}
return fn;
}
// c. Show how to compute Fn in O(lgn) time using only integer addition and multiplication.
// (Hint: Consider the matrix (0,1) and and its powers.) matrix[0][0] if fibona number
// (1,1)
// f(0)=a.00, f(1)=(a^2).00, f(n)=(a^(n+1)).00
public static FibonaMatrix fibonaByMatrixPower(int n) {
if(n<1) throw new IllegalArgumentException("Fibona(n) by matrix power, n>=1");
if (n == 1) {
return FibonaMatrix.getFibonaMatrix();
}
FibonaMatrix fibHalf = fibonaByMatrixPower(n>>1);
FibonaMatrix fib = FibonaMatrix.multiply(fibHalf, fibHalf);
if((n & 1) == 1) {
fib = FibonaMatrix.multiply(fib, FibonaMatrix.getFibonaMatrix());
}
return fib;
}
//F(n)为[0,1,1,1]^n+1的[0][0],这个可用数学归纳法证明, f(n)=(a^(n+1)).[0][0],
static class FibonaMatrix {
final private int[][] matrix = new int[2][2];
private FibonaMatrix() {
matrix[0][0] = 0;
matrix[0][1] = 1;
matrix[1][0] = 1;
matrix[1][1] = 1;
}
public static FibonaMatrix multiply(FibonaMatrix one, FibonaMatrix another) {
FibonaMatrix ret = getFibonaMatrix();
ret.matrix[0][0] = one.matrix[0][0] * another.matrix[0][0] + one.matrix[0][1]*another.matrix[1][0];
ret.matrix[0][1] = one.matrix[0][0] * another.matrix[0][1] + one.matrix[0][1]*another.matrix[1][1];
ret.matrix[1][0] = one.matrix[1][0] * another.matrix[0][0] + one.matrix[1][1]*another.matrix[1][0];
ret.matrix[1][1] = one.matrix[1][0] * another.matrix[0][1] + one.matrix[1][1]*another.matrix[1][1];
return ret;
}
public int getFibonaNb() {
return matrix[0][0];
}
public static FibonaMatrix getFibonaMatrix() {
return new FibonaMatrix();
}
}
}