为何我的Countdown求解器触发Python最大递归深度超限错误?
我正在实现热门电视节目《Countdown》的求解器,功能是给定6个数字和一个目标数字,遍历所有可能的解法直至找到一个并返回。不需要高度优化版本,只需要一个易于集成到更大程序中的简单函数。
运行代码时触发了最大递归深度超限错误,原以为只会执行5次递归调用(从6个数字到2个数字需要5次递归),不清楚错误原因。
求解器预期逻辑:
- 数字列表以字符串形式传入,循环中用4种运算组合每对数字(注意
a + b = b + a),并与目标值比对。 - 运算结果替换原列表中的两个数字,生成元素数少1的新列表,例如:
["7","9","50","25","75","100"] => ["63","50","25","75","100"] - 用新列表递归调用自身,直到列表只剩2个元素:
- 未找到解法返回"Q",后续调用也会返回"Q";
- 找到解法则返回运算字符串,比如
"(7 * 9)"。
- 递归返回时会替换表达式中的中间结果,最终生成完整表达式,比如
"(5 + (7 * 9))"。
用户提供的代码:
import itertools as i target=input("What is the target number? ") def solve(l): global count if len(l) == 2: count+=1 if int(l[0]) + int(l[1]) == target: return "("+l[0] +" + "+l[1]+")" count+=1 if int(l[0]) - int(l[1]) == target: return "("+l[0] +" - "+l[1]+")" count+=1 if int(l[0]) * int(l[1]) == target: return "("+l[0] +" * "+l[1]+")" count+=1 if int(l[0]) / int(l[1]) == target: return "("+l[0] +" / "+l[1]+")" count+=1 if int(l[1]) - int(l[0]) == target: return "("+l[0] +" - "+l[1]+")" count+=1 if int(l[1]) / int(l[0]) == target: return "("+l[1] +" / "+l[0]+")" else: return "Q" else: ct = list(i.combinations(l, 2)) for item in ct: count+=1 resulta1=int(item[0])+int(item[1]) if resulta1 == target: return "("+item[0] +" + "+item[1]+")" count+=1 resulta2=int(item[0])-int(item[1]) if resulta2 == target: return "("+item[0] +" - "+item[1]+")" count+=1 resulta3=int(item[0])*int(item[1]) if resulta3 == target: return "("+item[0] +" * "+item[1]+")" count+=1 resulta4=int(item[0])/int(item[1]) if resulta4 == target: return "("+item[0] +" / "+item[1]+")" count+=1 resulta5=int(item[1])-int(item[0]) if resulta5 == target: return "("+item[0] +" - "+item[1]+")" count+=1 resulta6=int(item[1])+int(item[0]) if resulta6 == target: return "("+item[1] +" / "+item[0]+")" intl = [el for el in l] intl.remove(item[0]) intl.remove(item[1]) newl=intl newl.append(str(resulta1)) res1=solve(newl) if res1 != "Q": return res1.replace(str(resulta1),"("+item[0] +" + "+item[1]+")") newl=intl newl.append(str(resulta2)) res2=solve(newl) if res2 != "Q": return res2.replace(str(resulta2),"("+item[0] +" - "+item[1]+")") newl=intl newl.append(str(resulta3)) res3=solve(newl) if res3 != "Q": return res3.replace(str(resulta3),"("+item[0] +" * "+item[1]+")") newl=intl newl.append(str(resulta4)) res4=solve(newl) if res4 != "Q": return res4.replace(str(resulta4),"("+item[0] +" / "+item[1]+")") newl=intl newl.append(str(resulta5)) res5=solve(newl) if res5 != "Q": return res5.replace(str(resulta5),"("+item[1] +" - "+item[0]+")") newl=intl newl.append(str(resulta6)) res6=solve(newl) if res6 != "Q": return res6.replace(str(resulta6),"("+item[1] +" / "+item[0]+")") else: return "Q" lis=input("Enter numbers separated by commas: ").split(",") count=0 solution = solve(lis) print(count)
递归超限的核心原因
列表引用错误导致无限递归
newl=intl是引用赋值,不是创建新列表,后续修改newl会直接改变intl的内容。比如第一次newl.append(str(resulta1))后,intl也会多出这个元素,后续再用newl=intl创建新列表时,长度会越来越长,永远无法触发len(l)==2的终止条件,导致无限递归。目标值类型不匹配
target是input()获取的字符串,代码中直接和整数运算结果比较(比如int(item[0])+int(item[1]) == target),这会永远不成立,导致所有路径都走到递归分支,进一步加剧递归次数。循环内提前返回"Q"
在for item in ct:循环的最后写了else: return "Q",导致第一次处理完一组数字的所有运算后,不管后续有没有其他组合,直接返回"Q",程序没有机会遍历所有可能的路径,同时错误的递归逻辑会反复触发调用。
修复方案
1. 修正目标值类型
将输入的target转为整数:
target = int(input("What is the target number? "))
2. 修复列表引用问题
创建新列表时使用拷贝,避免引用同一对象:
# 替换所有newl=intl的写法 newl = intl.copy() # 或 newl = list(intl)
3. 调整循环返回逻辑
将return "Q"移到循环外,只有遍历完所有数字组合都没找到解时才返回:
else: ct = list(i.combinations(l, 2)) for item in ct: # ... 原有运算处理逻辑 ... # 去掉循环内的else: return "Q" # 所有组合遍历完成后再返回Q return "Q"
4. 修正运算判断错误
比如resulta6的判断逻辑错误,应该是除法运算而非加法:
resulta6 = int(item[1]) / int(item[0]) if resulta6 == target: return "("+item[1] +" / "+item[0]+")"
同时注意除法的浮点数精度问题,建议用绝对值差判断:
if abs(resulta4 - target) < 1e-9:
5. 修正终止分支的表达式错误
比如int(l[1]) - int(l[0])的判断中,返回的表达式应该对应正确的运算顺序:
if int(l[1]) - int(l[0]) == target: return "("+l[1] +" - "+l[0]+")"
内容的提问来源于stack exchange,提问作者Shaken not Stirred

