题目描述(中等难度)

113. Path Sum II - 图1

112 题 的升级版,给定一个sum,输出从根节点开始到叶子节点,和为sum 的所有路径可能。

直接在 112 题 的基础上改了,解法没有新内容,大家可以过去看一看。

解法一 递归

112 题 的解法是下边的样子。

  1. public boolean hasPathSum(TreeNode root, int sum) {
  2. if (root == null) {
  3. return false;
  4. }
  5. return hasPathSumHelper(root, sum);
  6. }
  7. private boolean hasPathSumHelper(TreeNode root, int sum) {
  8. //到达叶子节点
  9. if (root.left == null && root.right == null) {
  10. return root.val == sum;
  11. }
  12. //左孩子为 null
  13. if (root.left == null) {
  14. return hasPathSumHelper(root.right, sum - root.val);
  15. }
  16. //右孩子为 null
  17. if (root.right == null) {
  18. return hasPathSumHelper(root.left, sum - root.val);
  19. }
  20. return hasPathSumHelper(root.left, sum - root.val) || hasPathSumHelper(root.right, sum - root.val);
  21. }

这里的话我们需要一个ans变量来保存所有结果。一个temp变量来保存遍历的路径。需要注意的地方就是,java中的list传递的是引用,所以递归结束后,要把之前加入的元素删除,不要影响到其他分支的temp

  1. public List<List<Integer>> pathSum(TreeNode root, int sum) {
  2. List<List<Integer>> ans = new ArrayList<>();
  3. if (root == null) {
  4. return ans;
  5. }
  6. hasPathSumHelper(root, sum, new ArrayList<Integer>(), ans);
  7. return ans;
  8. }
  9. private void hasPathSumHelper(TreeNode root, int sum, ArrayList<Integer> temp, List<List<Integer>> ans) {
  10. // 到达叶子节点
  11. if (root.left == null && root.right == null) {
  12. if (root.val == sum) {
  13. temp.add(root.val);
  14. ans.add(new ArrayList<>(temp));
  15. temp.remove(temp.size() - 1);
  16. }
  17. return;
  18. }
  19. // 左孩子为 null
  20. if (root.left == null) {
  21. temp.add(root.val);
  22. hasPathSumHelper(root.right, sum - root.val, temp, ans);
  23. temp.remove(temp.size() - 1);
  24. return;
  25. }
  26. // 右孩子为 null
  27. if (root.right == null) {
  28. temp.add(root.val);
  29. hasPathSumHelper(root.left, sum - root.val, temp, ans);
  30. temp.remove(temp.size() - 1);
  31. return;
  32. }
  33. temp.add(root.val);
  34. hasPathSumHelper(root.right, sum - root.val, temp, ans);
  35. temp.remove(temp.size() - 1);
  36. temp.add(root.val);
  37. hasPathSumHelper(root.left, sum - root.val, temp, ans);
  38. temp.remove(temp.size() - 1);
  39. }

解法二 DFS 栈

112 题 中解法二讲的是BFS,但是对于这道题由于我们要保存一条一条的路径,而BFS是一层一层的进行的,到最后一层一次性会得到很多条路径。这就导致遍历过程中,我们需要很多list来保存不同的路径,对于这道题是不划算的。

所以这里我们看 112 题 利用栈实现的DFS

看一下之前用后序遍历实现的代码。

  1. public boolean hasPathSum(TreeNode root, int sum) {
  2. List<Integer> result = new LinkedList<>();
  3. Stack<TreeNode> toVisit = new Stack<>();
  4. TreeNode cur = root;
  5. TreeNode pre = null;
  6. int curSum = 0; //记录当前的累计的和
  7. while (cur != null || !toVisit.isEmpty()) {
  8. while (cur != null) {
  9. toVisit.push(cur); // 添加根节点
  10. curSum += cur.val;
  11. cur = cur.left; // 递归添加左节点
  12. }
  13. cur = toVisit.peek(); // 已经访问到最左的节点了
  14. //判断是否满足条件
  15. if (curSum == sum && cur.left == null && cur.right == null) {
  16. return true;
  17. }
  18. // 在不存在右节点或者右节点已经访问过的情况下,访问根节点
  19. if (cur.right == null || cur.right == pre) {
  20. TreeNode pop = toVisit.pop();
  21. curSum -= pop.val; //减去出栈的值
  22. pre = cur;
  23. cur = null;
  24. } else {
  25. cur = cur.right; // 右节点还没有访问过就先访问右节点
  26. }
  27. }
  28. return false;
  29. }

和解法一一样,我们需要ans变量和temp变量,同样需要注意temp是对象,是引用传递。

  1. public List<List<Integer>> pathSum(TreeNode root, int sum) {
  2. Stack<TreeNode> toVisit = new Stack<>();
  3. List<List<Integer>> ans = new ArrayList<>();
  4. List<Integer> temp = new ArrayList<>();
  5. TreeNode cur = root;
  6. TreeNode pre = null;
  7. int curSum = 0; // 记录当前的累计的和
  8. while (cur != null || !toVisit.isEmpty()) {
  9. while (cur != null) {
  10. toVisit.push(cur); // 添加根节点
  11. curSum += cur.val;
  12. /************修改的地方******************/
  13. temp.add(cur.val);
  14. /**************************************/
  15. cur = cur.left; // 递归添加左节点
  16. }
  17. cur = toVisit.peek(); // 已经访问到最左的节点了
  18. // 判断是否满足条件
  19. if (curSum == sum && cur.left == null && cur.right == null) {
  20. /************修改的地方******************/
  21. ans.add(new ArrayList<>(temp));
  22. /**************************************/
  23. }
  24. // 在不存在右节点或者右节点已经访问过的情况下,访问根节点
  25. if (cur.right == null || cur.right == pre) {
  26. TreeNode pop = toVisit.pop();
  27. curSum -= pop.val; // 减去出栈的值
  28. /************修改的地方******************/
  29. temp.remove(temp.size() - 1);
  30. /**************************************/
  31. pre = cur;
  32. cur = null;
  33. } else {
  34. cur = cur.right; // 右节点还没有访问过就先访问右节点
  35. }
  36. }
  37. return ans;
  38. }

112 题 没什么区别,主要是注意函数传对象的时候,我们传的不是对象的副本,只是传了一个引用。

windliang wechat

添加好友一起进步~

如果觉得有帮助的话,可以点击 这里 给一个 star 哦 ^^

如果想系统的学习数据结构和算法,强烈推荐一个我之前学过的课程,可以点击 这里 查看详情