1.给定整数N,返回斐波那契数列的第N项。
分析:斐波那契数列:1,1,2,3,5,8,…
F(1)=1; F(2)=1;F(N)=F(N-1)+F(N-2)
由上述的式子,我给出了第一种递归解法
(1)
public static int fN(int n){
if(n<1){
return 0;
}
if(n==1||n==2){
return 1;
}
return fN(n-1)+fN(n-2);
}
但是,此解法的时间复杂度为O(2^N),很显然,不是我们想要的,为此,我引入了第二种方法:
(2)斐波那契数列可以从左到右推出每一项的值
2=1+1; 3=2+1;…
public static int fN(int n) {
int result = 1;
int pre = 1;
int temp = 0;
if (n < 1) {
return 0;
}
if (n == 1 || n == 2) {
return 1;
}
for(int i=3;i<=n;i++) {
temp = result;
result = result + pre;
pre = temp;
}
return result;
}
观察上述代码,时间复杂度为O(N),依然不是我们想要的最优结果,我们希望用一个方法它的时间复杂度为O(logN),那如何实现呢?
在此,我引入了第三种方法:
(3)F(N)=F(N-1)+F(N-2),是一个二阶递推数列,则就可以用矩阵的乘法的形式表示:
(F(N),F(N-1))=(F(N-1),F(N-2))O(22)
O(2*2):表示2行2列的状态矩阵
由前四项解得;状态矩阵为:{{1,1,},{1,0}}
推导过程如下:
代码实现:
public int[][] muliMatrix(int[][] m1,int[][] m2){
int[][] result=new int[m1.length][m2[0].length];
for(int i=0;i<m1.length;i++){
for(int j=0;j<m2[0].length;j++){
for(int k=0;k<m2.length;k++){
result[i][j]+=m1[i][k]*m2[k][j];
}
}
}
return result;
}
//求矩阵的n 次方
public int[][] Powermatrix(int[][] m, int n){
int[][] result=new int[m.length][m[0].length];
for(int i=0;i<result.length;i++){
result[i][i]=1; //先把result设为单位矩阵,1
}
int[][] temp=m;
for(;n!=0;n=n>>1){
if((n&1)!=0){
result=muliMatrix(result,temp);
}
temp=muliMatrix(temp,temp);
}
return result;
}
public int fN(int n){
if(n<1){
return 0;
}
if(n==1||n==2){
return 1;
}
int[][] m={{1,1},{1,0}};
int[][] result=Powermatrix(m,n-2);
return result[0][0]+result[1][0];
}
此方法的时间复杂度为:O(logN)
因为相当于将问题转换成了求一个矩阵N次方的问题。
补充问题:
输入一个整数n,算最少需要多少步它能变成斐波那契数列
分析:
要想算最少的步数,则:
第一步:找到一个大于等于整数n的斐波那契数记为x
第二步:找到它的前一个斐波那契数记为y
第三步:比较|x-n|,|y-n|,得到的最小的便为我们需要的结果。
程序实现:
public class FiBoNac {
public static int fN(int n){
if(n<1){
return 0;
}
if(n==1||n==2){
return 1;
}
return fN(n-1)+fN(n-2);
}
public static int getStep(int n){
int m=0;
int x=0;
while(m>=0){
if(fN(m)>=n){
x=fN(m);
break;
}
else{
m++;
}
}
int y=fN(m-1);
return Math.min(abs(y-n),abs(x-n));
}
public static void main(String[] args) {
Scanner scan=new Scanner(System.in);
int n=scan.nextInt();
System.out.println(getStep(n));
}
}