题目描述:
给定整数N,返回斐波那契数列的第N项。
n | 0 | -1 | -2 | -3 | -4 | -5 | -6 | -7 | -8 | … |
---|---|---|---|---|---|---|---|---|---|---|
Fib(n) | 0 | 1 | -1 | 2 | -3 | 5 | -8 | 13 | -21 | … |
解题思路
首先是O(2^n)的解法,除第一项和第二项以外,如果N为正整数,则F(n)=F(n-2)+F(n-1),如果N为负整数,则F(n) = F(n-2)-F(n-1)。于是暴力递归的方法如下:
/**
* 使用递归的方法
*
* @param n 要计算的数字
* @param isPositive: 是否是正数,如果是,则为true, 否则为false
* @return
*/
private static BigInteger fib_1(int n, boolean isPositive) {
if (n == 0) {
return BigInteger.valueOf(0);
} else if (n == 1 || n == -1) {
return BigInteger.valueOf(1);
} else if (isPositive) {
return fib_1(n - 2, isPositive).add(fib_1(n - 1, isPositive));
} else {
return fib_1(n + 2, isPositive).subtract(fib_1(n + 1, isPositive));
}
}
使用暴力递归的方法没有记录每个中间数值,因此有很多重复计算的问题,所以,我们考虑使用动态规划的方法,记录每个中间数值,时间复杂度为O(N)。代码如下:
/**
* 使用动态规划的方法
*
* @param n: 要计算的数字
* @param isPositive:是否为正整数
* @return
*/
private static BigInteger fib_2(int n, boolean isPositive) {
if (n == 0) {
return BigInteger.valueOf(0);
}
if (n == 1 || n == -1) {
return BigInteger.valueOf(1);
}
// 使用Math的abs函数,计算n的绝对值,将其作为构建动态规划数组的大小
int size = Math.abs(n);
// 创建动态规划数组,记录每个阶段的数值
BigInteger[] dp = new BigInteger[size + 1];
dp[0] = BigInteger.valueOf(0);// 第一个位置为0
dp[1] = BigInteger.valueOf(1);// 第二个位置为1
for (int i = 2; i <= size; i++) {
if (isPositive) {
dp[i] = dp[i - 2].add(dp[i - 1]);
} else {
dp[i] = dp[i - 2].subtract(dp[i - 1]);
}
}
return dp[size];
}
当然,还有其他时间复杂度更低的方法,比如使用矩阵乘法的方式,可以做到时间复杂度为O(logN)。有兴趣的读者可以自行研究。