递归回溯中状态应通过参数传递而非全局变量,遵循“做选择→递归→撤销选择”三步闭环,路径和约束需手动还原,剪枝基于当前参数状态,避免隐式状态泄漏。

在递归回溯中,方法调用状态不是靠额外变量“记住”,而是自然蕴含在函数调用栈和参数/局部变量中。关键在于:**把当前决策路径、约束条件和待选集合,通过参数传入,而非依赖全局或静态变量**。
用参数承载状态
每次递归调用都应显式传入当前已做的选择(如路径列表)、剩余可选元素(如未使用数字/字符)、以及当前满足的约束(如已选和、已用行/列标记等)。
- 路径状态(如
List<integer> path</integer>)建议传副本或回溯后手动还原——推荐后者,避免频繁拷贝开销 - 约束状态(如布尔数组
boolean[] used或位掩码int mask)直接传引用或值,修改后需在递归返回前撤销 - 不推荐用类字段存状态,否则多线程或嵌套调用易出错;若必须用,需确保每次递归前重置
回溯时精准还原
状态还原不是“清空所有”,而是仅撤销本次递归做的改动。典型模式是“做选择 → 递归 → 撤销选择”三步闭环。
- 添加元素到路径?对应地移除它
- 标记
used[i] = true?对应设为false - 累加和
sum += x?对应sum -= x - 避免在递归前深拷贝整个状态对象——性能差;优先用可变结构+手动回退
剪枝依赖当前状态判断
剪枝逻辑必须基于当前调用帧的状态参数,而不是全局快照。例如:
- 全排列中,若
used[i]为真,跳过该数 - 组合总和中,若
sum + candidates[i] > target,直接 break(前提是数组已排序) - N皇后中,检查当前
(row, col)是否与已有皇后冲突——只查已填的前row行
避免隐式状态泄漏
方法内新建的对象(如 new ArrayList())若作为参数传入下一层,要确认是否被后续递归修改。常见陷阱:
- 错误:传入同一个
ArrayList实例,子递归 add 后父层看到脏数据 → 应传新实例或严格管理增删时机 - 正确:路径用一个 list,每次 add 后递归,返回前 remove;约束用数组/位图,修改后必恢复
- 调试时可在递归入口打印关键状态(如
path、sum、mask),验证状态流转是否符合预期
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











