神奇的兔子数列——算法学习笔记


【点击此处跳转笔记正文】

Python 官网:https://www.python.org/


  • Free:大咖免费“圣经”教程《 python 完全自学教程》,不仅仅是基础那么简单……

  • My CSDN主页、My HOT博、My Python 学习个人备忘录
  • 好文力荐、 老齐教室

  自学并不是什么神秘的东西,一个人一辈子自学的时间总是比在学校学习的时间长,没有老师的时候总是比有老师的时候多。
            —— 华罗庚


等风来,不如追风去……

这是我参加“14天阅读挑战赛”第一周第三篇

神奇的兔子数列——算法学习笔记_第1张图片

点击查看“14天阅读挑战赛”详情,《趣学算法第二版》1.4 神奇的兔子数列。



跟着小玉老师学算法
神奇的“兔子数列”
(递归、循环,哪个更好?)


  假设第1个月有1对初生的兔子,第2个月进入成熟期,第3个月开始生育兔子,而1对成熟的兔子每月会生1对兔子,兔子永不死去……那么,由1对初生的兔子开始,12个月后会有多少对兔子呢?
  兔子数列即斐波那契数列,它的发明者是意大利数学家莱奥纳尔多·斐波那契(Leonardo Fibonacci,1170—1250)。1202年,莱奥纳尔多撰写了《算盘全书》(Liber Abaci),该书是一部较全面的初等数学著作。书中系统地介绍了印度—阿拉伯数码及其演算法则,以及中国的“盈不足术”;此外还引入了负数,并研究了一些简单的一次同余式组。

  根据分析第一、二个月没有兔子新增数量都是1;第三个月成熟期的兔子会生一只兔子,总数2;第四月成熟期的兔子会生兔子,上月生的兔子成熟,总数3;第五月两只成熟的兔子生小兔子,上月生的成熟,总数5;第五月三只成熟的兔子生小兔子,上月生的成熟,总数8;……兔子这样一直繁衍下去……
  由兔子繁殖规律可见,每月新生兔子数都是上上个月的总数。

神奇的兔子数列公式图

神奇的兔子数列——算法学习笔记_第2张图片
  根据从兔子繁殖分析出的事件特性,可以用递归算法编写代码实现任意项的数列项推演。

递归代码

def resursive_rabbit(n):
    ''' 递归兔子数列 '''
    if n == 1 or n == 2:
        return 1
    else:
        return resursive_rabbit(n-1) + resursive_rabbit(n-2)

运行效果截图
神奇的兔子数列——算法学习笔记_第3张图片
神奇的兔子数列——算法学习笔记_第4张图片
  这?效率有点儿低啊能不能优化下哩?这主要是在递推和回归在计算和存储上费时费力。那就用列表和循环来试试。

代码

def for_rabbit(n):
    ''' for循环优化兔子数列 '''
    fib = [1]*n
    
    for i in range(2, n):
        fib[i] = fib[i-1] + fib[i-2]

    return fib[-1]

运行效果截图
神奇的兔子数列——算法学习笔记_第5张图片
  这!这么快?
只是用一个列表来存储前面的项而已哦。等等,来算个10000项。
神奇的兔子数列——算法学习笔记_第6张图片
  耗时居然远远小于0.1秒。先不定义整个数列长度的列表,就第一、二项,后面的计算出来append到列表中,会不会更快?

代码

def for_rabbit_append(n):
    ''' for+append循环优化兔子数列 '''
    fib = [1, 1]
    
    for i in range(2, n):
        fib.append(fib[i-1] + fib[i-2])

    return fib[-1]

效果截屏图片
在这里插入图片描述

  和直接先定义n个元素长度的列表,几无差异(还是计算第10000项)。还可以优化不?只计算第几项,用列表存储整个数列,是不是有点儿浪费?用两个变量暂存上一项、上上项何如?

代码

def for_rabbit_ab(n):
    ''' for + a,b循环优化兔子数列 '''
    a, b = 1, 1

    for i in range(2, n):
        fib_new = b + a
        b, a = fib_new, b

    return b

代码运行效果截屏图片
神奇的兔子数列——算法学习笔记_第7张图片
  还是讲得第10000项,时间又少了一半!

这神奇的兔子数列,还没通项公式哩,用她来试试:
神奇的兔子数列——算法学习笔记_第8张图片

代码

def formula_rabbit(n):
    ''' 通项公式兔子数列 '''
    from math import sqrt
    a, b = ((1+sqrt(5))/2)**n, ((1-sqrt(5))/2)**n
    return 1/sqrt(5) * ( a - b )

运行效果截图
神奇的兔子数列——算法学习笔记_第9张图片
计算第10000项数字表示溢出报错截屏图片
神奇的兔子数列——算法学习笔记_第10张图片
  由试炼可见,通项公式不但有浮点数计算误差,还可以算太多的项。速度也比不上列表+循环。所以最好不好用通项公式来整。

试试用三个优化的循环都计算一遍第10000项:
神奇的兔子数列——算法学习笔记_第11张图片
耗时还是远远小于0.1秒。


  一般来讲,同一需求都可以设计几种算法。当重复太多,递归费时费力,就要找出一个更优算法。我从优化算法的过程中,真切地体会到算法之美!


回页首

mypycolor完整源码(源码较长,点此跳过源码)

#!/sur/bin/nve python
# coding: utf-8

'''

神奇的兔子数列——裴波拉契数列

filename = rabbit_fib.py

Author:梦幻精灵_cq

date:2022-10-21

'''


from  time import localtime, time


# 打印颜色设置字符。
text = '    假设第1个月有1对初生的兔子,第2个月进入成熟期,第3个月开始生育兔子,而1对成熟的兔子每月会生1对兔子,兔子永不死去……那么,由1对初生的兔子开始,12个月后会有多少对兔子呢?\n    兔子数列即斐波那契数列,它的发明者是意大利数学家莱奥纳尔多·斐波那契(Leonardo Fibonacci,1170—1250)。1202年,莱奥纳尔多撰写了《算盘全书》(Liber Abaci),该书是一部较全面的初等数学著作。书中系统地介绍了印度—阿拉伯数码及其演算法则,以及中国的“盈不足术”;此外还引入了负数,并研究了一些简单的一次同余式组。'
blue = '\033[34m'
red = '\033[91m'
green = '\033[92;5m'
gray = '\033[90m'
offall = '\033[0m'

def resursive_rabbit(n):
    ''' 递归兔子数列 '''
    if n == 1 or n == 2:
        return 1
    else:
        return resursive_rabbit(n-1) + resursive_rabbit(n-2)

def for_rabbit(n):
    ''' for循环优化兔子数列 '''
    fib = [1]*n
    
    for i in range(2, n):
        fib[i] = fib[i-1] + fib[i-2]

    return fib[-1]

def for_rabbit_append(n):
    ''' for+append循环优化兔子数列 '''
    fib = [1, 1]
    
    for i in range(2, n):
        fib.append(fib[i-1] + fib[i-2])

    return fib[-1]

def for_rabbit_ab(n):
    ''' for + a,b循环优化兔子数列 '''
    a, b = 1, 1

    for i in range(2, n):
        fib_new = b + a
        b, a = fib_new, b

    return b
    
def formula_rabbit(n):
    ''' 通项公式兔子数列 '''
    from math import sqrt
    a, b = ((1+sqrt(5))/2)**n, ((1-sqrt(5))/2)**n
    return 1/sqrt(5) * ( a - b )




if __name__ == '__main__':
    print(f"\n{green}{' 神奇的兔子数列 '.center(43, '~')}\n\n{gray}{text}{offall}")

    while True:
        try:
            n = int(input(f"\n{'':>8}第{blue} n {offall}项({blue}如 28{offall}):"))
            break
        except Exception as error:
            print(f"{red}{' 请输入整数! '.center(44, '~')}{offall}", end='\r')

    print(f"\n{gray}{' 机器正在运算…… '.center(44, '~')}{offall}", end='\r')
    t0 = time()

    #print(f"{' '*50}{gray}{resursive_rabbit.__doc__},{offall}第{blue} {n} {offall}项:{green}{resursive_rabbit(n)}\n\n{green}{'~'*50}{offall}")
    print(f"{' '*50}{gray}{for_rabbit.__doc__},{offall}第{blue} {n} {offall}项:{green}{for_rabbit(n)}\n\n{green}{'~'*50}{offall}")
    print(f"{' '*50}{gray}{for_rabbit_append.__doc__},{offall}第{blue} {n} {offall}项:{green}{for_rabbit_append(n)}\n\n{green}{'~'*50}{offall}")
    print(f"{' '*50}{gray}{for_rabbit_ab.__doc__},{offall}第{blue} {n} {offall}项:{green}{for_rabbit_ab(n)}\n\n{green}{'~'*50}{offall}")
    #print(f"{' '*50}{gray}{formula_rabbit.__doc__},{offall}第{blue} {n} {offall}项:{green}{formula_rabbit(n)}\n\n{green}{'~'*50}{offall}")

    print(f"\n{'':>14}程序用时{green}{time()-t0:10.6f}{offall} 秒。")
    y, M, d, h, m, s = localtime()[:6]
    input(f"{'~'*14} {blue}{y}-{M:02}-{d:02}{offall} {green}{h:02}:{m:02}:{s:02}{offall} {'~'*15}")


回页首

__上一篇:__ 猜数字小游戏——算法学习笔记

__下一篇:__ 

我的HOT博:

    • New:给定字符串提取姓名(字符串、list、re“零宽断言”)(1051阅读)
    • New:我的 Python.color() (Python 色彩打印控制)(1125阅读)
    • New:python清屏(1290阅读)
    • 回车符、换行符和回车换行符(1322阅读)
    • Linux 脚本文件第一行的特殊注释符(井号和感叹号组合)的含义(1171阅读)
    • pandas 数据类型之 Series(1224阅读)
    • 聊天消息敏感词屏蔽系统(字符串替换 str.replace(str1, *) )(1270阅读)
    • 练习:银行复利计算(用 for 循环解一道初中小题)(1188阅读)
    • pandas 数据类型之 DataFrame(2136阅读)
    • :班里有人和我同生日难吗?(蒙特卡洛随机模拟法)(2180阅读)
    • Python字符串居中显示(2359阅读)
    • 练习:求偶数和、阈值分割和求差( list 对象的两个基础小题)(1665阅读)
    • 用 pandas 解一道小题(2007阅读)
    • 可迭代对象和四个函数(1083阅读)
    • “快乐数”判断(1252阅读)
    • 罗马数字转换器(构造元素取模)(2159阅读)
    • Hot:罗马数字(转换器|罗生成器)(4750阅读)
    • Hot:让QQ群昵称色变的代码(36654阅读)
    • Hot:斐波那契数列(递归| for )(4071阅读)
    • 柱状图中最大矩形(1663阅读)
    • 排序数组元素的重复起止(1258阅读)
    • 电话拨号键盘字母组合(1402阅读)
    • 密码强度检测器(1986阅读)
    • 求列表平衡点(1837阅读)
    • Hot: 字符串统计(4308阅读)
    • Hot:尼姆游戏(聪明版首发)(3493阅读)尼姆游戏(优化版)(1175阅读)
    • 推荐条件 点阅破千

      回目录


      老齐漫画头像

      精品文章:

      • 好文力荐:《python 完全自学教程》齐伟书稿免费连载
      • OPP三大特性:封装中的property
      • 通过内置对象理解python'
      • 正则表达式
      • python中“*”的作用
      • Python 完全自学手册
      • 海象运算符
      • Python中的 `!=`与`is not`不同
      • 学习编程的正确方法

      来源:老齐教室


      回目录

      Python 入门指南【Python 3.6.3】


      好文力荐:

      • 全栈领域优质创作者——寒佬(还是国内某高校学生)好文:《非技术文—关于英语和如何正确的提问》,“英语”和“会提问”是学习的两大利器。

      • 【8大编程语言的适用领域】先别着急选语言学编程,先看它们能干嘛

      • 靠谱程序员的好习惯


      CSDN实用技巧博文:

      • 8个好用到爆的Python实用技巧
      • python忽略警告
      • Python代码编写规范
      • Python的docstring规范(说明文档的规范写法)

    你可能感兴趣的:(笔记,算法,python,算法)