Given a binary tree and a sum, find all root-to-leaf paths where each path's sum equals the given sum.
For example:
Given the below binary tree andsum = 22
,
5 / / 4 8 / / / 11 13 4 / / / / 7 2 5 1
[ [5,4,11,2], [5,8,4,5] ]
思路分析:这题是LeetCode Path Sum问题的变形题目,要求保存所有满足等于某个和的路径,仍然可以用DFS搜索解决,边DFS遍历树边保存下当前经过路径上的节点。和LeetCode Path Sum相比,有一个tricky的地方就是,回溯之后我们多了一句curPath.remove(curPath.size() - 1); 这是恢复“现场”,也就是把curPath恢复到递归调用之前的状态。那么问题来了,为什么我们只对curPath恢复现场,而不对curSum恢复现场呢(为何没有curSum-=curPath.get(curPath.size() - 1))?这就涉及到对java参数传递何时传值何时传引用(也就是地址)的理解了,简而言之,基础数据类型(int,char,……)传值,对象类型(Object,数组,容器……)传引用。所以,递归调用里面如果修改了curPath这个容器对象的内容,当回溯的时候我们需要恢复现场,而对于curSum这个int类型我们没必要这么操作,因为递归调用根本没有修改它的值,我们递归调用时对int传入的是一份拷贝,而对ArrayList传入的是引用或者地址。传引用还是传拷贝是很细致的问题,但是在递归实现的时候这些细节必须处理好,不然容易引入bug。时间复杂度O(n),空间复杂度O(klogn),k为合法路径条数。
AC Code
/** * Definition for binary tree * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode(int x) { val = x; } * } */ public class Solution { public List<List<Integer>> pathSum(TreeNode root, int sum) { List<List<Integer>> pathRes = new ArrayList<List<Integer>>(); List<Integer> curPath = new ArrayList<Integer>(); helper(root, sum, 0, pathRes, curPath); return pathRes; } public void helper(TreeNode root, int target, int curSum, List<List<Integer>> pathRes, List<Integer> curPath){ if(root == null) return; curSum += root.val; curPath.add(root.val); if(root.left == null && root.right == null && curSum == target) { pathRes.add(new ArrayList(curPath)); return; } if(root.left != null){ helper(root.left, target, curSum, pathRes, curPath); curPath.remove(curPath.size() - 1); } if(root.right != null){ helper(root.right, target, curSum, pathRes, curPath); curPath.remove(curPath.size() - 1); } } }