递归和终止
递归:在一个函数内部调用这个函数自身
循环:通过设置计算的初始值及终止条件,在一个范围内重复运算
对比:
- 递归实现代码更简洁,更易于实现
- 递归是函数自身调用,有时间和空间消耗(效率差,可能出现调用栈溢出)
- 递归中很多计算是重复的(用递归思路分析,自下而上循环实现)
题目
写一个函数,输入n,求斐波那契数列的第n项
1. 迭代:效率很低
有很多重复
// ======== 方法1:递归 ========
public long Fibonacci_Solution1(int n) {
if(n<=0)
return 0;
if(n==1)
return 1;
return Fibonacci_Solution1(n-1)+Fibonacci_Solution1(n-2);
}
2. 循环:理想解法
- 时间复杂度:
- 空间复杂度:
// ======== 方法2:循环 ========
public long Fibonacci_Solution2(int n) {
int[] result= {0,1};
if (n<2)
return result[n];
long fibNMinusOne =0;
long fibNMinusTwo=1;
long fibN=0;
for(int i=2;i<=n;++i) {
fibN=fibNMinusOne+fibNMinusTwo;
fibNMinusOne=fibNMinusTwo;
fibNMinusTwo=fibN;
}
return fibN;
}
3. 巧妙解法
- 时间复杂度:O(logN)
- 空间复杂度:O(logN)
利用数学归纳法,我们不难证明:
考虑乘方性质:
// ======== 方法3:基于矩阵乘法 ========
class Matrix2By2 //矩阵的定义
{
long m_00;
long m_01;
long m_10;
long m_11;
public Matrix2By2(long m00,long m01,long m10,long m11)
{
this.m_00=m00;
this.m_01=m01;
this.m_10=m10;
this.m_11=m11;
}
}
public Matrix2By2 MatrixMultiply(Matrix2By2 matrix1, Matrix2By2 matrix2) //矩阵的乘法
{
Matrix2By2 res=new Matrix2By2(
matrix1.m_00*matrix2.m_00+matrix1.m_01*matrix2.m_10,
matrix1.m_00*matrix2.m_10+matrix1.m_01*matrix2.m_11,
matrix1.m_10*matrix2.m_00+matrix1.m_11*matrix2.m_10,
matrix1.m_10*matrix2.m_10+matrix1.m_11*matrix2.m_11
);
return res;
}
public Matrix2By2 MatrixPower(int n) //矩阵的乘方
{
Matrix2By2 matrix;
if (n==1)
matrix=new Matrix2By2(1,1,1,0);
else if(n%2==0)
{
matrix=MatrixPower(n/2);
matrix=MatrixMultiply(matrix,matrix);
}
else
{
matrix=MatrixPower(n/2);
matrix=MatrixMultiply(matrix,matrix);
matrix=MatrixMultiply(matrix,new Matrix2By2(1,1,1,0));
}
return matrix;
}
//斐波那契数列
public long Fibonacci_Solution3(int n)
{
int[] result= {0,1};
if(n<2)
return result[n];
Matrix2By2 powerNMinus2=MatrixPower(n-1);
return powerNMinus2.m_00;
}
测试
- 功能测试(3、5、10)
- 边界测试(0、1、2)
- 性能测试(40、50、100)
// ======== 测试代码 ========
public static void Test(int n,int expected)
{
T10_Fibonacci solution=new T10_Fibonacci();
if(solution.Fibonacci_Solution1(n)==expected)
System.out.println("Test for "+n+" in solution1 passed.");
else
System.out.println("Test for "+n+" in solution1 failed.");
if(solution.Fibonacci_Solution2(n)==expected)
System.out.println("Test for "+n+" in solution2 passed.");
else
System.out.println("Test for "+n+" in solution2 failed.");
if(solution.Fibonacci_Solution3(n)==expected)
System.out.println("Test for "+n+" in solution3 passed.");
else
System.out.println("Test for "+n+" in solution3 failed.");
}
public static void main(String[] args) {
Test(0,0);
Test(1,1);
Test(2,1);
Test(3,2);
Test(4,3);
Test(5,5);
Test(6,8);
Test(7,13);
Test(8,21);
Test(9,34);
Test(10,55);
Test(40,102334155);
}