Skip to content

这道题原来可以用到JS这么多知识点!

JZ34 二叉树中和为某一值的路径(二)

题目描述

输入一颗二叉树的根节点root和一个整数expectNumber,找出二叉树中结点值的和为expectNumber的所有路径。

  1. 该题路径定义为从树的根结点开始往下一直到叶子结点所经过的结点
  2. 叶子节点是指没有子节点的节点
  3. 路径只能从父节点到子节点,不能从子节点到父节点
  4. 总节点数目为n

image-20220301123709450

javascript
输入:{10,5,12,4,7},22
返回值:[[10,5,7],[10,12]]
说明:返回[[10,12],[10,5,7]]也是对的
javascript
function TreeNode(x) {
    this.val = x;
    this.left = null;
    this.right = null;
}

我的解法

在解这道题时,题目中有两点值得注意:

  • 要求的是根到叶子节点
  • 和为给定数

显然,这是一道深度优先遍历出所有满足条件的路径

这里,我使用了cur来存储当前的累加和,使用了arr来存储当前的路径信息;

这两个的区别就是我们今天的重点:

  • cur为值变量,它是保存在栈之中的,作为参数传入函数中,函数修改了该值也不会对当前作用域的cur造成影响;

  • javascript
    {
      let cur = 0;
      ((cur)=>{cur = 1})(cur);
      console.log(cur);  // 1;
    }
  • arr作为引用变量,它是保存在堆里面,作为参数传入函数中时,它是传入的指针,所以修改的值也会影响到所有指向该对象的指针,这个对象此时只有一个;

  • javascript
    {
      const arr = [1,2,3];
      ((arr)=>{arr.push(4)})(arr);
      console.log(arr);  // [ 1, 2, 3, 4 ]
    }

所以我们要想arr在函数中修改不会影响到外部作用域,可以将其复制,然后再传入函数中,这时候对象就有两个了;

javascript
{
  const arr = [1,2,3];
  ((arr)=>{arr.push(4)})([...arr]);  // 这里使用ES6的语法进行复制
  console.log(arr);  // [ 1, 2, 3 ]
}

然后我们将其结合递归,递归其实也是内部有一个自己的函数,然后就是需要注意一下结束条件是如何返回的,下面就是该题的解法,该注释都注释了,如有问题请在评论区提出:

javascript
// 题解
function FindPath(root, expectNumber){
  let res = [];  // 存储符合该题条件的路径
  (function Dfs(root, cur, arr){
    if(!root) return;  // root为空时
    cur += root.val;  // 加上当前节点的值
    arr.push(root.val);  // 保存当前节点
    if(!root.left && !root.right && cur === expectNumber){
      res.push(arr);  // 符合条件的路径
    }
    Dfs(root.left, cur, [...arr]);  // 遍历左子树
    Dfs(root.right, cur, [...arr]); // 遍历右子树
  })(root, 0, []);
  return res;
}

当存储函数栈帧时,cur和arr会在之前的情况下添加节点,当弹出栈帧时,cur和arr会在之前的情况减少一个节点,因为返回到上一作用域了。