【Java】 剑指offer(9) 斐波那契数列及青蛙跳台阶问题
题目描述
一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。
思路分析:
数学归纳法寻找规律
经过计算,发现:
当n=1时,结果为1;
当n=2时,结果为2;
当n=3时,结果为4;
当n=4时,结果为8;
因此可以推出,f(n)=2^(n-1)。
每一个台阶都有跳与不跳两种情况(除最后一个台阶外),所以有2^(n-1)两种情况
代码实现:
public class Solution {
public int JumpFloorII(int target) {
int res =1;
if(target <= 2)
return target;
for(int i = 1; i<target; i++) {
res *= 2;
}
return res;
}
}
PS:Java实现幂运算,通过Math.pow()函数,没有^运算。Math.pow()函数的输入分别为底数和指数。输入和输出均为double型,所以需要强制转换。return (int)Math.pow(2,target-1);
拓展:
题目描述:
写一个函数,输入n,求斐波那契(Fibonacci)数列的第n项。
思路1
时间复杂度:O(n)的解法
如果直接写递归函数,由于会出现很多重复计算,效率非常底,不采用。
要避免重复计算,采用从下往上计算,可以把计算过了的保存起来,下次要计算时就不必重复计算:先由f(0)和f(1)计算f(2),再由f(1)和f(2)计算f(3)……以此类推,计算第n个时,只需要保存第n-1和第n-2项就可以。
代码实现:
public class Fibonacci {
public long Fib(long n) {
if(n<0)
throw new RuntimeException("下标错误,应从0开始!");
if (n == 0)
return 0;
if (n == 1)
return 1;
long prePre = 0;
long pre = 1;
long result = 1;
for (long i = 2; i <= n; i++) {
result = prePre + pre; //F(n)=F(n-1)+F(n-2)
prePre = pre; //更新F(n-2)
pre = result; //更新F(n-1)
}
return result; }
public void main(String[] args) {
}
}
思路二
时间复杂度为O(logn)的解法
斐波那契数列有以下公式(可由数学归纳法推导得到):
由上式可知,求f(n),只需要对矩阵求(n-1)次方即可,但此时时间复杂度仍为O(n)。利用乘方的性质
利用递归的思路计算乘方,即可将时间复杂度降低为O(longn)。这里给出对乘方函数的递归代码(引用):
Matrix2By2 MatrixPower(unsigned int n){
assert(n > 0);
Matrix2By2 matrix;
if(n == 1) {
matrix = Matrix2By2(1, 1, 1, 0); }
else if(n % 2 == 0) {
matrix = MatrixPower(n / 2);
matrix = MatrixMultiply(matrix, matrix); }
else if(n % 2 == 1) {
matrix = MatrixPower((n - 1) / 2);
matrix = MatrixMultiply(matrix, matrix);
matrix = MatrixMultiply(matrix, Matrix2By2(1, 1, 1, 0)); }
return matrix;
}
矩形覆盖问题
题目描述:
用n个21的小矩形无重叠地覆盖一个2n的大矩形,总共有多少种方法?
当n = 1时,有一种方法。
当n = 2时,有两种方法。
当n >= 3时,和斐波那契数列类似。第一步竖着放,有f(n-1)种方法;第一步横着放,有f(n-2)种方法。所以f(n)=f(n-1)+f(n-2)。
总结:
1、求n次方时,可以利用递归来降低时间复杂度;
2、斐波那契数列的实际问题扩展