二叉树根到叶路径递归代码问题排查:为何路径被合并为一条?
问题分析与修复方案
你的这段递归代码出现「所有路径合并成一条」的问题,核心原因是复用了同一个List<Integer> l对象,且没有正确做回溯操作,具体问题点拆解如下:
1. 引用传递导致的路径污染
Java中集合是引用类型,当你执行lists.add(l)时,并没有把当前路径的副本存入lists,而是存入了l对象的引用。后续对l的所有修改(比如添加、删除元素)都会同步影响lists中已经保存的「路径」,最终所有条目指向的都是同一个不断被修改的列表。
2. 缺少回溯操作,路径节点无法回退
在递归访问左/右子树前,你执行了l.add(root.val),但递归返回后没有将这个节点从l中移除。这就导致左子树的路径节点会被带到右子树的路径中,不同分支的节点全部堆积在同一个列表里,最终变成一条包含所有节点的「大路径」。
3. 叶子节点处理逻辑冗余且错误
当遇到叶子节点时,你额外执行了l.add(root.val),但实际上如果统一在递归开头先添加当前节点,这里的重复添加会导致叶子节点被存入两次;同时直接把l加入lists的问题和第一条一致,还是引用传递的坑。
修正后的代码示例
下面是修复后的递归逻辑,解决了上述所有问题:
private void rec(TreeNode root, List<Integer> l, List<List<Integer>> lists) { if (root == null) return; // 1. 先将当前节点加入路径 l.add(root.val); // 2. 处理叶子节点:创建当前路径的副本存入lists if (root.left == null && root.right == null) { lists.add(new ArrayList<>(l)); } else { // 3. 递归访问左右子树 rec(root.left, l, lists); rec(root.right, l, lists); } // 4. 回溯:移除当前节点,回到父节点的路径状态 l.remove(l.size() - 1); }
关键修复点说明:
- 回溯操作:递归返回后执行
l.remove(l.size() - 1),确保离开当前节点时,路径列表恢复到进入该节点前的状态,避免不同分支的节点互相干扰。 - 副本存入:遇到叶子节点时,用
new ArrayList<>(l)创建当前路径的副本,这样lists中保存的是独立的路径对象,后续修改l不会影响已保存的路径。 - 统一节点添加逻辑:把当前节点的添加放在递归开头,避免叶子节点的重复添加,逻辑更简洁。
内容的提问来源于stack exchange,提问作者blanchey
相关产品推荐
相关产品推荐

