斐波那契数列简介:
- 第一个月:有 1 对兔子①
- 第二个月:兔子①进入成熟期,还是 1 对
- 第三个月:兔子①生了一对兔子②,第三个月就有 2 对兔子
- 第四个月:兔子①生了一对兔子③,兔子②进入成熟期,这个月有 3 对兔子
- 第五个月:兔子①生了一对兔子④,兔子②生了一对兔子⑤,兔子③进入成熟期,这个月有 5 对兔子
- 第六个月:兔子①生了一对兔子⑥,兔子②生了一对兔子⑦,兔子③生了一对兔子⑧,兔子④进入成熟期,兔子⑤进入成熟期,这个月二有 8 对兔子
公式:
想到斐波那契数列(兔子数列)就很容易想到递归算法
代码示例:
long long Fib(int n) {
if (n < 0) return -1;
if (n == 1 || n == 2) return 1;
return Fib(n - 1) + Fib(n - 2);
}
递归算法写起来比较简单,但当 n 较大时,时间复杂度太高了(重复运算了很多数据)。
所以这里为了避免这种爆炸式的增加,运用规律,从第三项开始,后一项等于前两项之和。
代码实例:
long long Fib(int n) {
long long a = 1, b = 1, c = 0;
if (n <= 0) return -1;
if (n == 1 || n == 2) return 1;
if (n > 2) {
for (int i = 3; i <= n; ++i) {
c = a + b;
a = b;
b = c;
}
return c;
}
}
- 循环里的 a = b; b = c; 是什么意思 ?
这个方法通过更新值的方式不断往后计算,节省了空间和时间,参考下图:
下面还有一种方式,与上面的方式相似,但使用数组进行存储数据,访问数据的前两个数,将他们加起来,得到当前值。
代码示例:
long long Fib(int n) {
long long temp = 0;
long long* a = new long long[n + 1];
a[1] = a[2] = 1;
if (n <= 0) {
return -1;
}
else {
for (int i = 3; i <= n; ++i) {
a[i] = a[i - 1] + a[i - 2];
}
temp = a[n];
}
delete[] a;
return temp;
}
- 创建一个 n + 1 大小的数组,为什么是 n + 1 ?
前两个数据 1 是确定的,n 为 1 时,就创建两个空间,防止下面 a[2] 越界,当然也可以对 n 进行分析判断。
- 临时变量 temp 的作用是什么 ?
temp 保存 a[n] 的值,是为了能在函数内销毁 new 出来的 a 空间(堆区空间)。
- for 循环条件怎么确定的?
可以从最简单的 3 开始理解,当 n == 3 时这个循环只能执行一次,将 i 的初始值定为 3 ,判断条件为 i <= n,让 i 递增,而数组要通过下标的方式访问,可以写成 i = (i - 1) + (i - 2),随着 i 增加数据也不断往后移动。