递归视角下

复制代码
def listSum(numbers):
    if not numbers:
        return 0
    else:
        (f, rest) = numbers
    return f + listSum(rest)

myList = (1, (2, (3, (4,None))))
total = listSum(myList)
print(total)

while循环何时退出? 恐怕是while循环技巧所在,即选择恰当的变量作为退出循环的条件判断。

下面的栗子选择了哪个变量作为退出条件?

原题来自宁波第23届中小学信息比赛小学组决赛最后一道题。尝试用python代替原题要求的pascal count.pas/exe)

问题描述: 小Q的编程技术在一次搭积木比赛中也成了秘密武器。原来,比赛的规则是这样的:给你N个小木块(全部为一样大小的正方体)。快速搭成如下图规则的形状(下图为5层的规模),要求层数为最大限度。

由于小Q编了个程序,只要输入小木块的个数N,就可以马上求出最多可以搭几层,还剩几个,所以小Q每次都是一次成功,从不需要翻工,速度也就领先了,你会编小Q这样的程序吗?

【输入数据】

输入文件count.in:文件中只有一个整数N,表示小木块的个数,已知1≤N≤2^31。

【输出数据】

输出文件count.out:文件中有两行整数,第一行是最多可以堆的层数,第二行是剩余的小木块

Python语言的搭积木的诀窍 解法仅供参考

图片

递归的妙处:

第一条:每次递归都能将问题规模缩减下来。

第二条:对应递归终止条件,递归必须有个出口,不然会陷入无限递归当中。

第三条:将递归问题细分为更小的递归问题,然后再进行递归调用。

首先,只需要找到相邻两层之间数量关系,较大层数和小木块数量之间的关系表达为为consumer()函数

请看图:第1层是1,第2层是3,第3层用掉的木块是x,那么前3层用掉的木块总数是前2层用掉的总数,再加上第3层的木块数量。

留意:前3层和第3层所指不同,显然前3层包含第3层。持续倒推,就可以建立起第n层和第1层之间的数量关系。

第n-1层需要多少个小木块作为输入参数,

复制代码
x = consumer(n-1)

推出第n层需要多少小木块,

复制代码
consumer(n)=consumer(n-1) + 0.5*(n**2+n)

为啥是第2层开始,总能表达为

复制代码
consumer(n-1) + 0.5*(n**2+n)

为何1-> n 层的cube总的数量 = 第 n-1 层数量 + 0.5*(n**2+n)

符合以上数学关系的理由是第 n 层木块数量与 n 存在关系,不妨从求解三角形的面积公式得到灵感:

1+2+3+....n = 0.5*(n**2+n)

第n层的平面图计算高斯数

复制代码
please enter the cube numeber:20
4, 0

please enter the cube numeber:100
7, 16.0

please enter the cube numeber:1000
17, 31.0

但python递归的问题爆栈在随手将 n 大到离谱时如约而至!呵呵

复制代码
please enter the cube numeber:10000000000000

...
RecursionError: maximum recursion depth exceeded in comparison

那么,这时候有两个办法:

1、设法取消递归栈的上限:996 次; 2、或者改用循环的递推实现;

如何理解递归和循环?

SOLID原则:

分离出子函数layerSum(n)计算第 n 层有多少cube;

主函数 consumeWhile(total)判断累积cube超过total为退出循环的条件判断;

*可以与递归写法的结果比较是否一致

复制代码
# SOLID分离原则 
def layersSum(n):
    # 第 n 层有多少cube
    return 0.5 *(n**2 + n)

上述可以灵活修改每一层的几何形状,如改为正方形等等;

复制代码
def consumeWhile(total):
    # 表达相邻两层之间的数量关系
    # cur,upper = layers(1),layers(2)
    # upper变量是从 1-n 层共有多少cube
    cur,layer = 0,0
    while cur <= total:
        cur += layersSum(layer)
        if cur == total:
            return layer,0
        elif cur > total:
            return layer-1,total - (cur-layersSum(layer))
        layer += 1
        
        
total = 100000000
print(consumeWhile(total))

(842, 153956.0)

递归的写法优雅而有趣,但实际项目工程中并不是首选。正如在while循环中看到当 total 数字很大时,递归的不仅运算花费的时间多且易溢出而报错。

这时循环的写法系统的开销更少。

本文由mdnice多平台发布

相关推荐
2401_895521348 小时前
SpringBoot Maven快速上手
spring boot·后端·maven
disgare8 小时前
关于 spring 工程中添加 traceID 实践
java·后端·spring
ictI CABL8 小时前
Spring Boot与MyBatis
spring boot·后端·mybatis
小江的记录本10 小时前
【Linux】《Linux常用命令汇总表》
linux·运维·服务器·前端·windows·后端·macos
yhole13 小时前
springboot三层架构详细讲解
spring boot·后端·架构
香香甜甜的辣椒炒肉13 小时前
Spring(1)基本概念+开发的基本步骤
java·后端·spring
白毛大侠14 小时前
Go Goroutine 与用户态是进程级
开发语言·后端·golang
ForteScarlet14 小时前
从 Kotlin 编译器 API 的变化开始: 2.3.20
android·开发语言·后端·ios·开源·kotlin
大阿明14 小时前
SpringBoot - Cookie & Session 用户登录及登录状态保持功能实现
java·spring boot·后端
Binary-Jeff14 小时前
Spring 创建 Bean 的关键流程
java·开发语言·前端·spring boot·后端·spring·学习方法