经典算法大全51例——2.斐波那契数列(兔子数列)

算法目录合集

地址

   算法目录合集

说明

  该地址指向所有由本人自己所经历的算法习题(也有可能仅仅是一个入门的案例或者是经典案例),仅仅为我做过而且比较有意思的,也许还会有一些我自己想出来的,出于兴趣写在这里,具体格式我会在下面列明,总目录也会在这里出现,方便查阅以及自己进行复习回顾。

题目

  Fibonacci为1200年代的欧洲数学家,在他的着作中曾经提到:「若有一只免子每个月生一只小免子,一个月后小免子也开始生产。起初只有一只免子,一个月后就有两只免子,二个月后有三只免子,三个月后有五只免子(小免子投入生产)……类似的道理也可以用于植物的生长,这就是Fibonacci数列,一般习惯称之为费氏数列,例如以下: 1、1 、2、3、5、8、13、21、34、55、89……

原理分析

  斐波那契数列是一个非常有意思的数列,只不过它是由Fibonacci从一个兔子问题引出的,所以又叫做兔子数列。我们从最基本的数学思维来入手,我们第一次接触的数列是什么?等差等比,所以一切数列我们都可以在次基础上演化,思考,去寻找规律。
  而对于这个题,我们先看看Fibonacci是怎么引入这个问题的,首先,小兔子不生,一个后变成大兔子,大兔子会生,并且没有空怀期,也就是说每天增加的数量是前一天的大兔子数量,那么也就定性了——这不太可能是一个以乘积为规则的数列,明显是要以差值来进行约束变化规则的。
  有了方向,我们就要开始对数列进行分析了:1、1 、2、3、5、8、13、21、34、55。这列数字的特点一眼看不出来,那就试试后项减去前项,寻找他们的差有没有什么特点:他们的差组成的数列如下:0、1、1、2、3、5、8、13、21,等等!! 你们看出了什么?没错,这组数列的差居然除了第一项和原数列相同:

数列对比

  从表格看,也就是说:

f1 (1) + f2 (1) = f1 (2)
f1 (2) + f2 (2) = f1 (3)
f1 (3) + f2 (3) = f1 (4)
……
f1 (n-1) + f2 (n-1) = f1 (n)

  以此类推,那么既然差数列和原数列长的一样,何不把 f2 (n)替换成 f1 (n)呢,于是上面表达式可以变形为:

f1 (1) + 0 = f1 (2) 因为第一个f2 并没有与之对应的f1 ,所以直接用数值表示
f1 (2) + f1 (1) = f1 (3)
f1 (3) + f1 (2) = f1 (4)
……
f1 (n-1) + f1 (n-2) = f1 (n)

  所以就得出了核心的表达式:

  • f(n) = f(n - 1) + f(n - 2) ( n > 1)
  • f(n) = n ( n =1 , 0)

代码实现——Java

/**
 * @author g55zhw93
 */
public class Fibonacci{
    public int climbStairs(int n) {
        int result = 0;
        if (n < 0) {
            return 0;
        }
        if (n == 0 || n == 1) {
            return 1;
        }
        int[] values = new int[n + 1];
        values[0] = 1;
        values[1] = 1;
        for (int i = 2; i <= n; i++) {
            values[i]=values[i-1]+values[i-2];
        }
        return values[n];
    }

相关题目其他变形:

1.爬楼梯(来源:力扣LeetCode)

  第一个典型变形就是爬楼梯的问题,题目详见——力扣——70.爬楼梯(简单难度)——学会将实例化的问题剖析为规律性问题
  其实这里用到的思想是一个类似于递归的思想,但是解题时候并不需要递归;

这道题其实可以分成多个子问题,爬第n阶楼梯的方法数量,等于 2 部分之和,即:
爬上 n−1 阶楼梯的方法数量。因为再爬1阶就能到第n阶
爬上 n−2 阶楼梯的方法数量,因为再爬2阶就能到第n阶
也就是说, f(n) = f(n - 1) + f(n - 2)

  这不就转化成了斐波那契数列问题了。这里仅仅做一个简单的分析,全面分析在上面文章有,有兴趣的可以看看

2.兔子成熟期拉长

  这个变形是我自己瞎想的,总得给自己找点儿事儿不是?原题是一月一成熟,那么我们一点儿一点儿增加,先看看2月一成熟的情况:
斐波那契变形数列对比2月一成熟

  从表格看,可以得出

f1 (1) + f2 (1) = f1 (2)
f1 (2) + f2 (2) = f1 (3)
f1 (3) + f2 (3) =f1 (4)
……
f1 (9) + f2 (9) = f1 (10)
f1 (10) + f2 (10) = f1 (11)
……
f1 (n-1) + f2 (n-1) =f1 (n)

  以此类推,那么既然差数列和原数列长的一样,何不把 f2 (n)替换成 f1 (n)呢,于是上面表达式可以变形为:

f1 (1) + 0 = f1 (2)
f1 (2) + 0 = f1 (3)
f1 (3) + f1 (1) = f1 (4)
……
f1 (9) + f1 (7) = f1 (10)
f1 (10) + f1 (8) = f1 (11)
……
f1 (n-1) + f1 (n-3) = f1 (n)

斐波那契变形数列对比3月一成熟
  从表格看,可以得出

f1 (1) + f2 (1) = f1 (2)
f1 (2) + f2 (2) = f1 (3)
f1 (3) + f2 (3) =f1 (4)
……
f1 (9) + f2 (9) = f1 (10)
f1 (10) + f2 (10) = f1 (11)
……
f1 (n-1) + f2 (n-1) =f1 (n)

  以此类推,那么既然差数列和原数列长的一样,何不把 f2 (n)替换成 f1 (n)呢,于是上面表达式可以变形为:

f1 (1) + 0 = f1 (2)
f1 (2) + 0 = f1 (3)
f1 (3) + 0 = f1 (4)
……
f1 (9) + f1 (6) = f1 (10)
f1 (10) +f1 (7) = f1 (11)
……
f1 (n-1) + f1 (n-4) = f1 (n)

  后面就继续写了,我们发现了一个规律:

m月一成熟 兔子在n月的数目表达式
1 f1 (n-1) + f1 (n-2) = f1 (n)
2 f1 (n-1) + f1 (n-3) = f1 (n)
3 f1 (n-1) + f1 (n-4) = f1 (n)
…… ……
m f1 (n-1) + f1 (n - 1 - m) = f1 (n)

  迎刃而解~~~~

官方题解

分析

  依说明,我们可以将费氏数列定义为以下:

  • f(n) = f(n - 1) + f(n - 2) ( n > 1)
  • f(n) = n ( n =1 , 0)

代码——C语言

#include <stdlib.h>
#define N 20

int main(void) {
	int Fib[N] = {0};
	int i;
	Fib[0] = 0;
	Fib[1] = 1;
	for(i = 2; i < N; i++)
		Fib[i] = Fib[i-1] + Fib[i-2];
	for(i = 0; i < N; i++)
		printf("%d ", Fib[i]);
		printf("\n");
	return 0;
}

拓展

  说完了正儿八经的东西,想给大家看点儿其他的东西:

1.黄金矩形

斐波那契矩形
  这个其实是斐波那契数列的另一种解题思路:下一个正方形面积的边长肯定是之前的两个边长之和,这样拼成的矩形又被称为斐波那契矩形,而这个矩形随着数列的递增,其实是越来越接近黄金矩形的:
黄金矩形

2.等角螺线

  由这个矩形中的正方形画出的弧,构成的曲线又叫做等角螺线,随着矩形的增大,这个图形就会变的非常好看:
等角螺线
  自然界中很多蜗牛,海里的壳类生物都拥有这种黄金分割的自然之美
自然界中的黄金分割

3.设计

  同时也有很多人,把这种黄金分割用于设计:
设计中的黄金分割1
设计中的黄金分割2
  不得不说,大神之所以是大神,是因为人家确实是大神,哈哈哈哈,这不禁让我想起了鲁迅的名句::“数学的应用并不唯一,我只觉得NB!!!”
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/g55zhw93/article/details/108234945