算法思想一:回溯法(先序遍历)
解题思路:
使用回溯法解决,其包含 先序遍历 + 路径记录 两部分
先序遍历: 按照 “根、左、右” 的顺序,遍历树的所有节点。
路径记录: 在先序遍历中,记录从根节点到当前节点的路径。当路径为根节点到叶节点形成的路径且各节点值的和等于目标值 sum 时,将此路径加入结果列表。
路径记录: 在先序遍历中,记录从根节点到当前节点的路径。当路径为根节点到叶节点形成的路径且各节点值的和等于目标值 sum 时,将此路径加入结果列表。
算法流程:
pathSum(root, sum) 函数:
初始化: 结果列表 res ,路径列表 path 。
返回值: 返回 res 即可。
pathSum(root, sum) 函数:
初始化: 结果列表 res ,路径列表 path 。
返回值: 返回 res 即可。
recur(root, tar) 函数:
递推参数: 当前节点 root ,当前目标值 tar 。
终止条件: 若节点 root 为空,则直接返回。
递推工作:
1、路径更新: 将当前节点值 root.val 加入路径 path ;
2、目标值更新: tar = tar - root.val(即目标值 tar 从 sum 减至 0 );
3、路径记录: 当 root 为叶节点 且路径和等于目标值 ,则将此路径 path 加入 res 。
4、先序遍历: 递归左 / 右子节点。
5、路径恢复: 向上回溯前,需要将当前节点从路径 path 中删除,即执行 path.pop()
图解:
代码展示:
Python版本
class Solution: def pathSum(self , root , sum ): # write code here # 初始化 返回数组 路径数组 res, path = [], [] def recur(root, tar): if not root: return path.append(root.val) tar -= root.val if tar == 0 and not root.left and not root.right: # 路径符合要求 加入res res.append(list(path)) # 递归 左右子树 recur(root.left, tar) recur(root.right, tar) path.pop() # 回溯 recur(root, sum) return res
复杂度分析:
时间复杂度 O(N) : N 为二叉树的节点数,先序遍历需要遍历所有节点。空间复杂度 O(N) : 最差情况下,即树退化为链表时,path 存储所有树节点,使用 O(N) 额外空间。
算法思想二:递归
解题思路:
从根节点到叶子节点遍历他所有的路径,返回他所有路径中和等于sum的节点,这里有两种实现方式,一种是减,一种是加。减就是从根节点开始,用sum不断的减去遍历到的每一个节点,一直到叶子节点,在减去叶子节点之前查看sum是否等于叶子节点,如果等于说明我们找到了一组 图解:
此解题思路图解和采用先序遍历同样思想,唯一区别在于此方法在递归的时候没有依次移除 subList 存储的节点
代码展示:
JAVA版本
public class Solution { /** * * @param root TreeNode类 * @param sum int整型 * @return int整型ArrayList<ArrayList<>> */ public ArrayList<ArrayList<Integer>> pathSum (TreeNode root, int sum) { // write code here ArrayList<ArrayList<Integer>> result = new ArrayList<>(); dfs(root, sum, new ArrayList<>(), result); return result; } public void dfs(TreeNode root, int sum, ArrayList<Integer> list, ArrayList<ArrayList<Integer>> result) { //如果节点为空直接返回 if (root == null) return; //因为list是引用传递,为了防止递归的时候分支污染,我们要在每个路径 //中都要新建一个subList ArrayList<Integer> subList = new ArrayList<>(list); //把当前节点值加入到subList中 subList.add(new Integer(root.val)); //如果到达叶子节点,就不能往下走了,直接return if (root.left == null && root.right == null) { //如果到达叶子节点,并且sum等于叶子节点的值,说明我们找到了一组, //要把它放到result中 if (sum == root.val) result.add(subList); //到叶子节点之后直接返回,因为在往下就走不动了 return; } //如果没到达叶子节点,就继续从他的左右两个子节点往下找,注意到 //下一步的时候,sum值要减去当前节点的值 dfs(root.left, sum - root.val, subList, result); dfs(root.right, sum - root.val, subList, result); } }
复杂度分析:
时间复杂度 O(N) : N 为二叉树的节点数,递归遍历所有节点。空间复杂度 O(N) : 最差情况下,即树退化为链表时,subList 存储所有树节点,使用 O(N) 额外空间。