题目描述
输入一棵二叉树和一个整数,打印出二叉树中节点值的和为输入整数的所有路径。从树的根节点开始往下一直到叶节点所经过的节点形成一条路径。
示例:
给定如下二叉树,以及目标和 sum = 22,5
/ \
4 8
/ / \
11 13 4
/ \ / \
7 2 5 1
返回:[
[5,4,11,2],
[5,8,4,5]
]
提示:节点总数 <= 10000
参考思路:回溯
- 先序遍历: 按照 “根、左、右” 的顺序,遍历树的所有节点。
- 路径记录: 在先序遍历中,记录从根节点到当前节点的路径。当路径为 ① 根节点到叶节点形成的路径 且 ② 各节点值的和等于目标值 sum 时,将此路径加入结果列表。
pathSum(root, sum)
函数:
- 初始化: 结果列表
array
,路径列表list
。 - 返回值: 返回 array 即可。
sumDFS(root, sum, temp,list) 函数:
- 递推参数: 当前节点 root ,目标值sum ,当前节点值的和 temp,节点路径集合列表list 。
- 终止条件: 若节点 root 为空,则直接返回。
- 递推工作:
- 路径更新: 将当前节点值 root.val 加入路径 list ;
- 目标值更新: temp += root.val(即目标值 temp 从 0增加至sum );
- 路径记录: 当 ① root 为叶节点 且 ② 路径和等于目标值 ,则将此路径 list 加入array 。
- 先序遍历: 递归左 / 右子节点。
- 路径恢复: 向上回溯前,需要将当前节点从路径 list 中删除,即执行 list.remove() 。
小tips:
- 记录路径时若直接执行 array.add(list) ,则是将 list 对象加入了 array ;后续 list 改变时, array 中的 list 对象也会随之改变,正确做法:
array.add(new ArrayList<>(list))
,相当于复制了一个list
并加入到array
。 - 路径子节点集合值在向上回溯时不需要减掉之前路径节点相应的值,因为这里int值是深拷贝,基本数据类型传递给方法的是变量的值(深拷贝)而不是实际的存储值变量的地址(浅拷贝)
// 定义全局List存储二维数组
private List<List<Integer>> array = new ArrayList<>();
public List<List<Integer>> pathSum(TreeNode root, int sum) {
List<Integer> list = new ArrayList<>(); // 定义合理路径集合
sumDFS(root,sum,0,list); // dfs
return array;
}
public void sumDFS(TreeNode root, int sum, int temp, List<Integer> list) {
// 节点为空边界限制
if (root == null) {
return ;
}
temp += root.val; // 目前所以子节点的和
list.add(root.val); // 追加进节点路径集合
// 子节点路径和与目标值相等且左右子节点为空--避免负数节点情况
if (temp == sum && root.left == null && root.right == null) {
array.add(list);
}
// 递归左右子节点
if (root.left != null) {
sumDFS(root.left, sum, temp, list);
}
if (root.right != null) {
sumDFS(root.right, sum, temp, list);
}
// 回溯退回节点值
list.remove(list.size()-1);
}
复杂度分析:
时间复杂度 O(N) : N为二叉树的节点数,先序遍历需要遍历所有节点。
空间复杂度 O(N): 最差情况下,即树退化为链表时,list 存储所有树节点,使用 O(N) 额外空间。
作者:jyd
链接:https://leetcode-cn.com/problems/er-cha-shu-zhong-he-wei-mou-yi-zhi-de-lu-jing-lcof/solution/mian-shi-ti-34-er-cha-shu-zhong-he-wei-mou-yi-zh-5/