Python真约数求和程序结果错误排查及优化咨询
错误根源分析
你的代码核心问题是循环变量k的自增逻辑重复,导致命中约数判断时会跳过下一个整数:
- 当
n % k == 0条件成立时,你在if代码块内写了k += 1 - 紧接着if块结束后,又无条件执行了一行
k = k + 1
这就导致只要当前k是n的约数,单次循环k就会总共加2,直接跳过k+1这个数的判断,自然会漏掉2、4这类连续的约数:
- 计算36的约数时,k=1命中判断,if内k变成2,出if又加1变成3,直接跳过了k=2的校验;k=3命中判断时,if内k变成4,出if又加1变成5,跳过k=4的校验,总共少加了2+4=6,55-6=49,和你实际输出完全一致
- 计算102的约数时,k=1命中判断后直接跳到k=3,少加了2,114-2=112,和你实际输出一致
- 测试用例n=3返回1属于巧合:跳过的k=2本来就不是3的约数,没有影响最终结果
另外你代码里对k反复调用int()是多余操作,k从初始化开始就是整数类型,不需要重复转换。
基础修复版本
只需要把k的自增逻辑统一放到循环末尾,每次循环只自增1次,不要在if块内重复写自增逻辑即可,同时补上n≤1的边界判断:
def sum_divisors(n): # 小于等于1的数没有真约数,直接返回0 if n <= 1: return 0 k = 1 total = 0 while k < n: if n % k == 0: total += k k += 1 # 所有分支统一自增1,避免跳数 return total # 测试用例 print(sum_divisors(0)) # 0 print(sum_divisors(3)) # 1 print(sum_divisors(36)) # 55 print(sum_divisors(102)) # 114
运行后所有测试用例返回结果完全符合预期。
性能优化版本
上面的基础版时间复杂度是O(n),当n取值很大时运行效率很低。利用「约数成对出现」的特性,只需要遍历到√n就可以找到所有约数,时间复杂度可以降到O(√n),大数值场景下性能提升非常明显:
import math def sum_divisors(n): if n <= 1: return 0 total = 1 # 1是所有大于1的整数的真约数,直接初始化 sqrt_n = int(math.sqrt(n)) # 从2遍历到平方根即可,成对收集约数 for k in range(2, sqrt_n + 1): if n % k == 0: total += k pair = n // k # 避免重复加完全平方数的平方根,同时排除等于n本身的约数 if pair != k and pair != n: total += pair return total
优化点说明:
- 不需要从1遍历到n-1,遍历上限到n的平方根即可,比如计算1000000的真约数和,只需要循环1000次,远低于基础版的100万次
- 提前处理边界值,避免n=0、n=1时出现无意义的循环
- 去掉了冗余的类型转换,代码更简洁
内容的提问来源于stack exchange,提问作者Warrior
相关产品推荐
相关产品推荐

