递归视角下

复制代码
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多平台发布

相关推荐
义薄云天us6 分钟前
027_国际化与本地化
人工智能·后端·restful·claude code
独立开阀者_FwtCoder17 分钟前
Vue3 新趋势:请不要再用 Transition!最强动效库诞生!
前端·vue.js·后端
这里有鱼汤17 分钟前
Python菜鸟如何用AI写出高质量代码?这6招我亲测有效!
后端·python
风象南2 小时前
SpringBoot集成MyBatis的SQL拦截器实战
java·spring boot·后端
Victor3562 小时前
MySQL(142)如何解决索引碎片化问题?
后端
Victor3562 小时前
MySQL(141)如何处理重复数据问题?
后端
遥不可及~~斌3 小时前
Spring Boot RESTful API 设计指南:查询接口规范与最佳实践
spring boot·后端·restful
熟悉的新风景9 小时前
springboot项目或其他项目使用@Test测试项目接口配置-spring-boot-starter-test
java·spring boot·后端
晴空月明10 小时前
分布式系统高可用性设计 - 监控与日志系统
后端
songroom11 小时前
【转】Rust: PhantomData,#may_dangle和Drop Check 真真假假
开发语言·后端·rust