代码随想录算法训练营第十八天|● 513.找树左下角的值 ● 112. 路径总和 113.路径总和ii ● 106.从中序与后序遍历序列构造二叉树 105.从前序与中序遍历序列构造二叉树(JS写法)

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
在这里插入图片描述
方法一:BFS
直接想到的就是这种方法,返回最后一层的第一个元素[ [1],[2,3],[4,5,6],[7] ],一开始以为这样不能通过,因为下图这种情况,但是居然通过了,那就是这种情况也是最底层最左侧的
在这里插入图片描述

/**
 * Definition for a binary tree node.
 * function TreeNode(val, left, right) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.left = (left===undefined ? null : left)
 *     this.right = (right===undefined ? null : right)
 * }
 */
/**
 * @param {TreeNode} root
 * @return {number}
 */
var findBottomLeftValue = function(root) {
    let res = [];
    let queue = [root];
    while(queue.length){
        let len = queue.length;
        let subRes = [];
        while(len){
            let cur = queue.shift();
            subRes.push(cur.val);
            if(cur.left) queue.push(cur.left);
            if(cur.right) queue.push(cur.right);
            len--;
        }
        res.push(subRes);
    }
    return res[res.length-1][0];
};

112 路径总和

题目链接/文章讲解/视频讲解:https://programmercarl.com/0112.%E8%B7%AF%E5%BE%84%E6%80%BB%E5%92%8C.html
在这里插入图片描述
方法一:DFS递归,回溯,不是精简版的递归,体现了回溯思想(先减掉再加上,因为每一次遍历到底,也就是更改了cnt的值,如果这条路径不对,返回去需要更改路径,也就是说要把cnt复原)

/**
 * Definition for a binary tree node.
 * function TreeNode(val, left, right) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.left = (left===undefined ? null : left)
 *     this.right = (right===undefined ? null : right)
 * }
 */
/**
 * @param {TreeNode} root
 * @param {number} targetSum
 * @return {boolean}
 */
var hasPathSum = function(root, targetSum) {
    const traversal = (node,cnt) => {
        //确定终止条件
        //已经是叶子节点,且总和已经为0,则存在路径
        if(node.left === null && node.right === null && cnt === 0){
            return true;
        }
        //已经是叶子节点,但总和不为0,则不存在路径
        if(node.left === null && node.right === null && cnt !== 0){
            return false;
        }
        //单层循环逻辑
        if(node.left){
            cnt -= node.left.val;
            if(traversal(node.left,cnt)) return true;
            //回溯思想
            cnt += node.left.val;
        }
        if(node.right){
            cnt -= node.right.val;
            if(traversal(node.right,cnt)) return true;
            cnt += node.right.val;
        }
        return false;
    }
    if(root === null) return false;
    //注意,这里传入的总和要已经减去根节点的值
    return traversal(root,targetSum - root.val);
    

};

113 路径总和Ⅱ

在这里插入图片描述
方法一:递归
本题结合了112路径总和和257二叉树的所有路径,更多的是在112的基础上加了一个参数path

/**
 * Definition for a binary tree node.
 * function TreeNode(val, left, right) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.left = (left===undefined ? null : left)
 *     this.right = (right===undefined ? null : right)
 * }
 */
/**
 * @param {TreeNode} root
 * @param {number} targetSum
 * @return {number[][]}
 */
var pathSum = function(root, targetSum) {
    // 要遍历整个树找到所有路径,所以递归函数不需要返回值, 与112不同
    const res = [];
    const travelsal = (node,cnt,path) => {
        if(cnt === 0 && node.left === null && node.right === null){
            res.push([...path]);  //不能写res.push(path),要深拷贝
            return;
        }
        if(cnt !== 0 && node.left === null && node.right === null){
            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 === null) return [];
    //把根节点放进路径
    travelsal(root,targetSum - root.val,[root.val]);
    return res;

};

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

题目链接/文章讲解/视频讲解: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
在这里插入图片描述
思路:其实思路核心都是要根据后序来知道根节点的值,然后以此来划分左子树的区间和右子树的区间。
方法一:笨猪爆破组的方法,很详细
在这里插入图片描述
方法一:笨猪爆破组

/**
 * Definition for a binary tree node.
 * function TreeNode(val, left, right) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.left = (left===undefined ? null : left)
 *     this.right = (right===undefined ? null : right)
 * }
 */
/**
 * @param {number[]} inorder
 * @param {number[]} postorder
 * @return {TreeNode}
 */
var buildTree = function(inorder, postorder) {
    const map = {};
    //把inorder数组内的节点值和对应索引先用map存起来,方便找mid的位置
    for(let i = 0;i<inorder.length;i++){
        map[inorder[i]] = i;
    }
    const helper = (iStart,iEnd,pStart,pEnd) => {
        //指针交错了,返回null节点
        if(pStart > pEnd || iStart > iEnd){
            return null;
        }
        //根据后序数组里的最后一个值获取到根节点的值
        const rootVal = postorder[pEnd];
        //获取到根节点的值在中序数组中的位置,方便划分左子树和右子树
        const mid = map[rootVal];
        //获取到左子树的节点个数
        const leftNodeNum = mid-iStart;
        //创建根节点
        const root = new TreeNode(rootVal);
        //递归构建左子树
        root.left = helper(iStart,mid-1,pStart,pStart+leftNodeNum-1);
        //递归构建右子树
        root.right = helper(mid+1,iEnd,pStart+leftNodeNum,pEnd-1);
        return root;
    }
    return helper(0,inorder.length-1,0,postorder.length-1);
};

方法二:代码随想录
笨猪爆破组的方法没有使用indexof,而是使用了map,用空间换时间,所以时间复杂度很低,而代码随想录的方法由于使用了indexof所以时间复杂度很高。

/**
 * Definition for a binary tree node.
 * function TreeNode(val, left, right) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.left = (left===undefined ? null : left)
 *     this.right = (right===undefined ? null : right)
 * }
 */
/**
 * @param {number[]} inorder
 * @param {number[]} postorder
 * @return {TreeNode}
 */
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 从前序与中序遍历序列构造二叉树

在这里插入图片描述

/**
 * Definition for a binary tree node.
 * function TreeNode(val, left, right) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.left = (left===undefined ? null : left)
 *     this.right = (right===undefined ? null : right)
 * }
 */
/**
 * @param {number[]} preorder
 * @param {number[]} inorder
 * @return {TreeNode}
 */
var buildTree = function(preorder, inorder) {
    const map = {};
    for(let i = 0;i<inorder.length;i++){
        map[inorder[i]] = i;
    }
    const helper = (pStart,pEnd,iStart,iEnd) => {
        if(pStart > pEnd || iStart > iEnd){
            return null;
        }
        let rootVal = preorder[pStart];
        let root = new TreeNode(rootVal);
        let mid = map[rootVal];
        let leftNodeNum = mid - iStart;
        root.left = helper(pStart+1,pStart+leftNodeNum,iStart,mid-1);
        root.right = helper(pStart+leftNodeNum+1,pEnd,mid+1,iEnd);
        return root;

    }
    return helper(0,preorder.length-1,0,inorder.length-1);
};

思路和106一样,只是这次自己在写root.left和root.right的时候,觉得leftNodeNum和mid不应该是一样的吗,所以不太确定,虽然最后也还是没弄明白为什么两者不能替换,补充补充:一开始我之所以以为mid和leftNodeNum是一样的是因为我一直拿iStart=0,但之后的递归iStart并不一直是0,递归的过程还是有点迷糊。
在构建root.left时,我们应该使用leftNum而不是mid来确定左子树的范围。同样,在构建root.right时,应该使用mid+1而不是leftNum+1来确定右子树的范围,以确保正确的划分左右子树。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
代码随想录算法训练营是一个优质的学习和讨论平台,提供了丰富的算法训练内容和讨论交流机会。在训练营中,学员们可以通过观看视频讲解来学习算法知识,并根据讲解内容进行刷题练习。此外,训练营还提供了刷题建议,例如先看视频、了解自己所使用的编程语言、使用日志等方法来提高刷题效果和语言掌握程度。 训练营中的讨论内容非常丰富,涵盖了各种算法知识点和解题方法。例如,在第14天的训练营中,讲解了二叉树的理论基础、递归遍历、迭代遍历和统一遍历的内容。此外,在讨论中还分享了相关的博客文章和配图,帮助学员更好地理解和掌握二叉树的遍历方法。 训练营还提供了每日的讨论知识点,例如在第15天的讨论中,介绍了层遍历的方法和使用队列来模拟一层一层遍历的效果。在第16天的讨论中,重点讨论了如何进行调试(debug)的方法,认为掌握调试技巧可以帮助学员更好地解决问题和写出正确的算法代码。 总之,代码随想录算法训练营是一个提供优质学习和讨论环境的平台,可以帮助学员系统地学习算法知识,并提供了丰富的讨论内容和刷题建议来提高算法编程能力。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [代码随想录算法训练营每日精华](https://blog.csdn.net/weixin_38556197/article/details/128462133)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值