第六章 二叉树 part05(● 513.找树左下角的值 ● 112. 路径总和 113.路径总和ii ● 106.从中序与后序遍历序列构造二叉树 105.从前序与中序遍历序列构造二叉树)

学习目标:

● 513.找树左下角的值
● 112. 路径总和 113.路径总和ii
● 106.从中序与后序遍历序列构造二叉树 105.从前序与中序遍历序列构造二叉树


学习内容:● 513.找树左下角的值

题目链接/文章讲解/视频讲解:https://programmercarl.com/0513.%E6%89%BE%E6%A0%91%E5%B7%A6%E4%B8%8B%E8%A7%92%E7%9A%84%E5%80%BC.html
tip:在树的最后一行找到最左边的值。
层序遍历比递归更好理解

递归版本:
var findBottomLeftValue = function(root) {
    //首先考虑递归遍历 前序遍历 找到最大深度的叶子节点即可
    let maxPath = 0, resNode = null;
    // 1. 确定递归函数的函数参数
    const dfsTree = function(node, curPath) {
    // 2. 确定递归函数终止条件
        if(node.left === null && node.right === null) {
            if(curPath > maxPath) {
            maxPath = curPath;
            resNode = node.val;
            }
        }
        node.left && dfsTree(node.left, curPath+1);
        node.right && dfsTree(node.right, curPath+1);
    }
    dfsTree(root,1);
    return resNode;
};
层序遍历:

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

题目链接/文章讲解/视频讲解:https://programmercarl.com/0112.%E8%B7%AF%E5%BE%84%E6%80%BB%E5%92%8C.html

0112.路径总和

递归
// targetSum = targetSum-root.left.val   注意是root.left.val
/**
 * @param {treenode} root
 * @param {number} targetsum
 * @return {boolean}
 */
let haspathsum = function (root, targetsum) {
  // 递归法
  const traversal = (node, cnt) => {
    // 遇到叶子节点,并且计数为0
    if (cnt === 0 && !node.left && !node.right) return true;
    // 遇到叶子节点而没有找到合适的边(计数不为0),直接返回
    if (!node.left && !node.right) return false;

    //  左(空节点不遍历).遇到叶子节点返回true,则直接返回true
    if (node.left && traversal(node.left, cnt - node.left.val)) return true;
    //  右(空节点不遍历)
    if (node.right && traversal(node.right, cnt - node.right.val)) return true;
    return false;
  };
  if (!root) return false;
  return traversal(root, targetsum - root.val);

  // 精简代码:
  // if (!root) return false;
  // if (!root.left && !root.right && targetsum === root.val) return true;
  // return haspathsum(root.left, targetsum - root.val) || haspathsum(root.right, targetsum - root.val);
};
0113.路径总和-ii
// travelsal(root, targetsum - root.val, [root.val]); // 把根节点放进路径
// res.push([...path]); // 不能写res.push(path), 要深拷贝
递归

let pathsum = function (root, targetsum) {
  // 递归法
  // 要遍历整个树找到所有路径,所以递归函数不需要返回值, 与112不同
  const res = [];
  const travelsal = (node, cnt, path) => {
    // 遇到了叶子节点且找到了和为sum的路径
    if (cnt === 0 && !node.left && !node.right) {
      res.push([...path]); // 不能写res.push(path), 要深拷贝
      return;
    }
    if (!node.left && !node.right) return; // 遇到叶子节点而没有找到合适的边,直接返回
    // 左 (空节点不遍历)
    if (node.left) {
      path.push(node.left.val);
      travelsal(node.left, cnt - node.left.val, path); // 递归
      path.pop(); // 回溯
    }
    // 右 (空节点不遍历)
    if (node.right) {
      path.push(node.right.val);
      travelsal(node.right, cnt - node.right.val, path); // 递归
      path.pop(); // 回溯
    }
    return;
  };
  if (!root) return res;
  travelsal(root, targetsum - root.val, [root.val]); // 把根节点放进路径
  return res;
};

学习内容:● 106.从中序与后序遍历序列构造二叉树 105.从前序与中序遍历序列构造二叉树

题目链接/文章讲解/视频讲解:https://programmercarl.com/0106.%E4%BB%8E%E4%B8%AD%E5%BA%8F%E4%B8%8E%E5%90%8E%E5%BA%8F%E9%81%8D%E5%8E%86%E5%BA%8F%E5%88%97%E6%9E%84%E9%80%A0%E4%BA%8C%E5%8F%89%E6%A0%91.html

1.后序数组为0,空节点
2.后序数组最后一个元素为节点元素
3.寻找中序数组位置作为切割点
4.切中序数组
5.切后序数组
6.递归处理左区间右区间

注意确定切割的标准,是左闭右开,还有左开右闭,还是左闭右闭,这个就是不变量,要在递归中保持这个不变量。

前序和中序可以唯一确定一棵二叉树。
后序和中序可以唯一确定一棵二叉树。
前序和后序不能唯一确定一棵二叉树!,因为没有中序遍历无法确定左右部分,也就是无法分割。

从中序与后序遍历序列构造二叉树
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;
};
从前序与中序遍历序列构造二叉树

var buildTree = function(preorder, inorder) {
  if (!preorder.length) return null;
  const rootVal = preorder.shift(); // 从前序遍历的数组中获取中间节点的值, 即数组第一个值
  const index = inorder.indexOf(rootVal); // 获取中间节点在中序遍历中的下标
  const root = new TreeNode(rootVal); // 创建中间节点
  root.left = buildTree(preorder.slice(0, index), inorder.slice(0, index)); // 创建左节点
  root.right = buildTree(preorder.slice(index), inorder.slice(index + 1)); // 创建右节点
  return root;
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
好的,这里是求任意二叉树中第一条最长路径长度及其路径上各节点算法: 1. 定义一个全局变量 `max_length`,用于记录最长路径长度。 2. 定义一个函数 `dfs`,该函数的参数为当前节点 `node` 和当前路径长度 `path_length`,初始调用时 `node` 应为根节点,`path_length` 应为0。 3. 在 `dfs` 函数中,如果当前节点为空,则返回0。 4. 否则,分别递归遍历当前节点的左子树和右子树,分别得到左子树的最长路径长度 `left_length` 和右子树的最长路径长度 `right_length`。 5. 计算当前节点的最长路径长度 `node_length`,即左子树最长路径长度加右子树最长路径长度加1(因为要将当前节点算上)。 6. 如果 `node_length` 大于 `max_length`,则更新 `max_length` 为 `node_length`,并记录当前路径上各节点的。 7. 返回 `node_length`。 8. 最终返回 `max_length` 和记录的路径上各节点的。 下面是该算法的 Python 代码实现: ```python max_length = 0 path = [] def dfs(node, path_length): global max_length, path if not node: return 0 left_length = dfs(node.left, path_length) right_length = dfs(node.right, path_length) node_length = left_length + right_length + 1 if node_length > max_length: max_length = node_length path = [node.val] + path[:left_length] + path[left_length+right_length:] return max(left_length, right_length) + 1 dfs(root, 0) print("Max length:", max_length) print("Path:", path) ``` 其中,`root` 为二叉树的根节点。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值