代码随想录算法训练营day18| 513.找树左下角的值、 112. 路径总和 113.路径总和ii、106.从中序与后序遍历序列构造二叉树 105.从前序与中序遍历序列构造二叉树

513.找树左下角的值

题目链接/文章讲解/视频讲解

思路:

这道题可使用递归或者迭代方法来做 迭代更简单一点 ,到达叶子节点,也就是 left 和 right 都为 null 的时候,判断一下现在所在深度是不是大于最深的深度,如果是,更新一下答案值。最终更新结果就是最左边且深度最大的节点的值。尽管也会遍历右子树,但是深度不比左子树的深,也不会更新,也就是同样在最底层的左子树会优先赋值给 resNode。

代码实现

    var findBottomLeftValue = function (root) {
      let maxDepth = 0;
      let result = null;
      const traversal = function (root, depth) {
        if (root.left === null && root.right === null) {
          //当遇到叶子节点的时候,就需要统计一下最大的深度了,所以需要遇到叶子节点来更新最大深度。
          if (depth > maxDepth) {
            maxDepth = depth
            result = root.val
          }
          return
        }
        root.left && traversal(root.left, depth + 1)
        root.right && traversal(root.right, depth + 1)

        return
      }
      traversal(root, 1);
      return result
    };
    //层序遍历
    var findBottomLeftValue = function (root) {
      let queue = []
      if (root === null) {
        return null
      }
      queue.push(root);
      let resNode;
      while (queue.length) {
        let length = queue.length;
        for (let i = 0; i < length; i++) {
          let node = queue.shift()
          //记录最后一行的第一个节点的数值
          if (i === 0) {
            resNode = node.val
          }
          node.left && queue.push(node.left);
          node.right && queue.push(node.right);

        }
      }
      return resNode
    };

 112. 路径总和 113.路径总和ii

题目链接/文章讲解/视频讲解

思路

这道题 求单条路径用递归需要返回值 而求所有路径 则不需要

代码实现:

路径总和

 var hasPathSum = function (root, targetSum) {
      const traversal = function (root, count) {

        if (!root.left && !root.right && count === 0) { return true }
        if (!root.left && !root.right && count !== 0) { return false }
        if (root.left) {
          if (traversal(root.left, count - root.left.val)) {
            return true
          }
        }
        if (root.right) {
          if (traversal(root.right, count - root.right.val)) {
            return true
          }
        }

        return false
      }
      if (!root) {
        return false
      }
      return traversal(root, targetSum - root.val)
    };
    //迭代
    var hasPathSum = function (root, targetSum) {
      if (!root) {
        return false
      }
      let nodeArr = [root];
      let valArr = [0]
      while (nodeArr.length) {
        let node = nodeArr.shift()
        let val = valArr.shift()
        val += node.val
        if (node.left === null && node.right === null && val === targetSum) {
          return true
        }
        if (node.left) {
          nodeArr.push(node.left)
          valArr.push(val)

        }
        if (node.right) {
          nodeArr.push(node.right)
          valArr.push(val)
        }
      }
      return false
    };

路径总和ii:

 var pathSum = function (root, targetSum) {
      // 递归法
      // 要遍历整个树找到所有路径,所以递归函数不需要返回值, 与112不同
      const res = [];
      const traversal = (node, sum, path) => {
        // 遇到了叶子节点且找到了和为sum的路径
        if (sum === 0 && !node.left && !node.right) {
          res.push([...path])//深拷贝
          return;
        }
        if (!node.left && !node.right) {
          return;
        }
        if (node.left) {
          path.push(node.left.val);
          traversal(node.left, sum - node.left.val, path)
          path.pop()// 回溯
        }
        if (node.right) {
          path.push(node.right.val);
          traversal(node.right, sum - node.right.val, path)
          path.pop()// 回溯
        }
        return
      }
      if (!root) {
        return res
      }
      traversal(root, targetSum - root.val, [root.val])
      return res
    };
    //递归精简版
    var pathSum = function (root, targetSum) {
      // 递归法
      // 要遍历整个树找到所有路径,所以递归函数不需要返回值, 与112不同
      const res = [], pathArr = [];
      const traversal = (node, sum) => {
        // 遇到了叶子节点且找到了和为sum的路径
        pathArr.push(node.val)
        sum -= node.val
        if (sum === 0 && !node.left && !node.right) {
          res.push([...pathArr])//深拷贝

        }

        node.left && traversal(node.left, sum)
        node.right && traversal(node.right, sum)
        let cur = pathArr.pop()
        //总数需要减去当前节点的值 然后进行下一次递归
        sum -= cur
      }
      if (!root) {
        return res
      }
      traversal(root, targetSum)
      return res
    };
    //迭代
    var pathSum = function (root, targetSum) {
      if (!root) {
        return []
      }
      let nodeArr = [root];
      let resArr = [];// 记录符合目标和的返回路径
      let tempArr = [[]];// 对应路径
      let countArr = [0];//对应和
      while (nodeArr.length) {
        let curNode = nodeArr.shift()
        let curVal = countArr.shift();
        let curNodeArr = tempArr.shift()
        curVal += curNode.val;
        curNodeArr.push(curNode.val)
        // 为叶子结点,且和等于目标数,将此次结果数组push进返回数组中
        if (curNode.left === null && curNode.right === null && curVal === targetSum) {
          resArr.push(curNodeArr)
        }
        if (curNode.left) {
          nodeArr.push(curNode.left);
          countArr.push(curVal);
          tempArr.push([...curNodeArr])
        }
        if (curNode.right) {
          nodeArr.push(curNode.right);
          countArr.push(curVal);
          tempArr.push([...curNodeArr])
        }
      }
      return resArr
    }

106.从中序与后序遍历序列构造二叉树 105.从前序与中序遍历序列构造二叉树

题目链接/文章讲解/视频讲解

中后序:

  • 第一步:如果数组大小为零的话,说明是空节点了。

  • 第二步:如果不为空,那么取后序数组最后一个元素作为节点元素。

  • 第三步:找到后序数组最后一个元素在中序数组的位置,作为切割点

  • 第四步:切割中序数组,切成中序左数组和中序右数组 (顺序别搞反了,一定是先切中序数组)

  • 第五步:切割后序数组,切成后序左数组和后序右数组

  • 第六步:递归处理左区间和右区间

前中序是一样的道理

代码实现:

106.从中序与后序遍历序列构造二叉树

function TreeNode (val, left, right) {
      this.val = (val === undefined) ? 0 : val
      this.left = (left === undefined) ? null : left
      this.right = (right === undefined) ? null : right


    }
    var buildTree = function (inorder, postorder) {
      if (!inorder.length) {
        return null
      }
      //取出栈顶元素 也就是后序数组中的 根元素
      const rootVal = postorder.pop()
      let rootIndex = inorder.indexOf(rootVal)// 获取中间节点在中序遍历中的下标
      const root = new TreeNode(rootVal)
      root.left = buildTree(inorder.slice(0, rootIndex), postorder.slice(0, rootIndex))
      root.right = buildTree(inorder.slice(rootIndex + 1), postorder.slice(rootIndex))
      return root
    };

105.从前序与中序遍历序列构造二叉树

function TreeNode (val, left, right) {
      this.val = (val === undefined) ? 0 : val
      this.left = (left === undefined) ? null : left
      this.right = (right === undefined) ? null : right


    }
    var buildTree = function (preorder, inorder) {
      if (!inorder.length) {
        return null
      }
      //取出栈顶元素 也就是后序数组中的 根元素
      const rootVal = preorder.shift()
      let rootIndex = inorder.indexOf(rootVal)// 获取中间节点在中序遍历中的下标
      const root = new TreeNode(rootVal)

      //关于为何从0开始 是因为前序数组的第一个元素已经被取出来了所以从0开始
      root.left = buildTree(preorder.slice(0, rootIndex), inorder.slice(0, rootIndex))
      root.right = buildTree(preorder.slice(rootIndex), inorder.slice(rootIndex + 1))
      return root
    };

总结

今天总体偏难 需要注意 前后序是无法进行构造二叉树 因为前序后序虽然可以判别出根元素 但是无法切割左右部分,所以无法构造

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值