如何统计Python递归函数中执行的基础数学操作次数
如何统计Python递归函数中执行的基础数学操作次数
嘿,我来帮你搞定这个问题!你现在的核心问题是:手写的递归计数函数只考虑了foo里的少量固定操作,完全忽略了bar函数的操作次数,也没处理循环带来的动态操作量——毕竟循环次数和n直接相关,不能硬编码固定数值。咱们一步步拆解修正:
第一步:先搞定bar(k)的操作次数统计
首先得单独算出调用bar(k)时会执行多少次目标操作。先分析bar的逻辑:
- 不管
k多大,计算range(2, k+1)时都会执行1次+操作(算k+1) - 当
k>=2时,会进入for循环,每个i的操作包括:j = i-1:1次-- while循环的
j>0判断:共i次(从i-1降到0,要判断i次) - 每次while循环内:
i%j(1次%)、==0(1次==)、分支里的//或+(1次)、j = j-1(1次-),共4次操作,循环i-1次
基于这个分析,我们可以写出count_bar函数,用数学公式优化避免循环(大k时更高效):
def count_bar(k): total = 1 # 计算k+1的1次+操作 if k >= 2: # 公式计算i从2到k的总操作量:sum(5i - 3) sum_part = 5 * (k * (k + 1) // 2 - 1) - 3 * (k - 1) total += sum_part return total
比如k=1时返回1(只有k+1的1次+),k=2时返回8,和手动模拟的结果一致。
第二步:修正count_operations递归函数
现在我们要把foo(n)的每个分支拆解开,统计所有操作:基础判断/运算、递归调用、循环带来的操作,还要加上bar的调用次数。为了避免重复计算,用lru_cache缓存递归结果:
from functools import lru_cache @lru_cache(maxsize=None) def count_operations(n): if n == 0: # foo(0)的操作:n%3(1次%) + n==0判断(1次==) return 2 m = n % 3 if m == 0: # 基础操作:%、两次==判断、//、n+1的+、最后的+ base_ops = 1 + 1 + 1 + 1 + 1 + 1 # 循环部分:n次循环,每次*和+共2次操作,加上每个bar(4*i)的次数 loop_ops = 2 * n + sum(count_bar(4 * i) for i in range(1, n+1)) return base_ops + count_operations(n // 3) + loop_ops elif m == 1: # 基础操作:%、三次==判断、-、两次*、最后的+ base_ops = 1 + 1 + 1 + 1 + 1 + 2 + 1 return base_ops + count_operations(n - 1) + count_bar(n ** 3) else: # m == 2 # 基础操作:%、三次==判断、-、最后的+ base_ops = 1 + 1 + 1 + 1 + 1 + 1 loop_count = max(0, n - 2) # 每次循环:*、%、+ 三次操作 + bar(n)的次数 loop_ops = loop_count * (3 + count_bar(n)) return base_ops + count_operations(n - 2) + loop_ops
为什么你的原脚本不对?
- 完全忽略了
bar的操作:bar的操作次数和输入参数强相关,不是固定值,比如bar(1)有1次操作,bar(4)会有更多。 - 循环操作硬编码:比如
foo(n%3==0)里的for循环执行n次,每次都有操作和bar调用,不能用固定的4次代替。 - 基础操作计数错误:比如
n=1时,你没把bar(1)里的1次+算进去,导致结果偏差。
验证一下
count_operations(0)返回2,符合手动模拟的foo(0)操作次数count_operations(1)返回11,和你之前的模拟结果完全一致count_operations(2)返回8,手动模拟foo(2)的操作次数也能对上
这个方法不需要实际执行foo和bar的业务逻辑,直接通过数学推导计算操作次数,比你用类补丁的低效方法性能高得多,尤其是n较大时。
备注:内容来源于stack exchange,提问作者Geddez
相关产品推荐
相关产品推荐

