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

513. 找树左下角的值

题目:给定一个二叉树的 根节点 root,请找出该二叉树的 最底层 最左边 节点的值。假设二叉树中至少有一个节点。

提示:

  • 二叉树的节点个数的范围是 [1,104]
  • -231 <= Node.val <= 231 - 1 

思路:寻找树左下角的值,目标为树最低层,最左边的节点的值。这里注意如果这棵树最低层只有右叶子节点,但它相对来说也是最低层的左边 ,因此本题采用层序遍历,记录每层遍历的第一个节点的值即可。

注意:左下角是相对位置,右子树的右叶子节点也可以是“左下角”,层序遍历中注意比较层数是否为最深。

Java实现

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    private int Deep = -1;
    private int value = 0;
    public int findBottomLeftValue(TreeNode root) {
        value = root.val;
        findLeftValue(root,0);
        return value;
    }

    private void findLeftValue(TreeNode root,int deep){
        if(root == null){
            return ;
        }
        if(root.left == null && root.right == null){
            if(deep>Deep){
                value = root.val;
                Deep = deep;
            }
        }

        if(root.left != null){
            findLeftValue(root.left,deep+1);
        }
        if(root.right != null){
            findLeftValue(root.right,deep+1);
        }
    }
}

112. 路径总和

题目: 给你二叉树的根节点 root 和一个表示目标和的整数 targetSum 。判断该树中是否存在 根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和 targetSum 。如果存在,返回 true ;否则,返回 false 。叶子节点 是指没有子节点的节点。

提示:

  • 树中节点的数目在范围 [0, 5000] 内
  • -1000 <= Node.val <= 1000
  • -1000 <= targetSum <= 1000

思路:本题主要思路和 257. 二叉树的所有路径 一致,不同之处在于路径信息不输出,只进行比较,是否存在满足条件的距离总和。

注意:注意回溯

Java实现

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    private boolean result = false;
    public boolean hasPathSum(TreeNode root, int targetSum) {
        if(root==null){
            return result;
        }

        List<Integer> path = new ArrayList<>();
        equalPathSum(root,path,targetSum);

        return result;
    }

    private void equalPathSum(TreeNode root,List<Integer> path,int targetSum){
        path.add(root.val);
        if(root.left==null && root.right==null){    // 遇到叶子节点判断当前路径和是否满足条件
            int sum =0;
            for(int i=0;i<path.size();i++){
                sum += path.get(i);
            }
            if(sum==targetSum){
                result = true;   
            }
            return ;
        }

        // 递归和回溯
        if(root.left!=null){
            equalPathSum(root.left,path,targetSum);
            path.remove(path.size()-1);
        }
        if(root.right!=null){
            equalPathSum(root.right,path,targetSum);
            path.remove(path.size()-1);
        }
    }
}

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

题目: 给定两个整数数组 inorder 和 postorder ,其中 inorder 是二叉树的中序遍历, postorder 是同一棵树的后序遍历,请你构造并返回这颗 二叉树 。

提示:

  • 1 <= inorder.length <= 3000
  • postorder.length == inorder.length
  • -3000 <= inorder[i], postorder[i] <= 3000
  • inorder 和 postorder 都由 不同 的值组成
  • postorder 中每一个值都在 inorder 中
  • inorder 保证是树的中序遍历
  • postorder 保证是树的后序遍历

思路:根据后续遍历和中序遍历的数组生成原树,首先要明确后续遍历和中序遍历如何划分左右子树。后续遍历,从尾到头依次为根节点、右子树、左子树;中序遍历,从头到尾依次为左子树、根节点、右子树。根据不同遍历顺序的特点,结合使用。取后续遍历的最后一个元素,即为当前根节点,在中序遍历的数组中找到其下标位置,下标以前的都是左子树的部分,下标以后的都为右子树的部分,据此划分出两个新的中序遍历表。根据新生成的中序遍历中的元素个数划分出新的后续遍历表,这里注意,后续遍历表每次都从后向前退一个元素。

注意:本题基本思路在于划分,切割。在确定划分界限后,切割的区间范围要界定明了。

Java实现

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public TreeNode buildTree(int[] inorder, int[] postorder) {
        if(postorder.length == 0 || inorder.length == 0){
            return null;
        }
        return bulidHelper(inorder,0,inorder.length,postorder,0,postorder.length);
        // 初始切割划分,原始中序和后序数组
    }

    private TreeNode bulidHelper(int[] inorder,int inorderStart,int inorderEnd,
                                    int[] postorder,int postorderStart,int postorderEnd){
        if(postorderStart == postorderEnd){
            return null;
        }

        int rootVal = postorder[postorderEnd-1];
        TreeNode root = new TreeNode(rootVal);      // 根据后序遍历得到的根节点切割后形成新树
        int middleIndex;    // 根据后续遍历节点划分中序遍历元素,分出左右子树
        for(middleIndex = inorderStart;middleIndex<inorderEnd;middleIndex++){
            if(inorder[middleIndex]==rootVal){
                break;
            }
        }

        // 左子树区间范围左闭右开,右子树区间范围左开右闭
        int leftInorderStart = inorderStart;
        int leftInorderEnd = middleIndex;
        int rightInorderStart = middleIndex+1;
        int rightInordrEnd = inorderEnd;

        int leftPostorderStart = postorderStart;
        int leftPostorderEnd = postorderStart+(middleIndex-inorderStart);
        int rightPostorderStart = leftPostorderEnd;
        int rightPostorderEnd = postorderEnd-1;

        root.left = bulidHelper(inorder,leftInorderStart,leftInorderEnd,postorder,leftPostorderStart,leftPostorderEnd);
        root.right = bulidHelper(inorder,rightInorderStart,rightInordrEnd,postorder,rightPostorderStart,rightPostorderEnd);

        return root;


    }
}

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

题目: 给定两个整数数组 preorder 和 inorder ,其中 preorder 是二叉树的先序遍历, inorder 是同一棵树的中序遍历,请构造二叉树并返回其根节点。

提示:

  • 1 <= preorder.length <= 3000
  • inorder.length == preorder.length
  • -3000 <= preorder[i], inorder[i] <= 3000
  • preorder 和 inorder 均 无重复 元素
  • inorder 均出现在 preorder
  • preorder 保证 为二叉树的前序遍历序列
  • inorder 保证 为二叉树的中序遍历序列

思路:本题实质上与  106. 从中序与后序遍历序列构造二叉树 一致,区别在于采用前序遍历时,从头至尾依次为根节点、左子树、右子树,结合与中序遍历使用。

注意:前序遍历在划分新的两个前序遍历表时,右子树的区间范围可从右向左,根据右区间边界和右子树中序遍历元素个数生成。

Java实现

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public TreeNode buildTree(int[] preorder, int[] inorder) {
        if(preorder.length == 0 || inorder.length ==0){
            return null;
        }

        return buildHelper(inorder,0,inorder.length,preorder,0,preorder.length);
    }

    private TreeNode buildHelper(int[] inorder,int inorderStart,int inorderEnd,
                                    int[] preorder,int preorderStart,int preorderEnd){
        if(preorderStart == preorderEnd){
            return null;
        }

        int rootValue = preorder[preorderStart];
        TreeNode root = new TreeNode(rootValue);
        int middleIndex;
        for(middleIndex=inorderStart;middleIndex<inorderEnd;middleIndex++){
            if(inorder[middleIndex] == rootValue){
                break;
            }
        }

        int leftInorderStart = inorderStart;
        int leftInorderEnd = middleIndex;
        int rightInorderStart = middleIndex+1;
        int rightInorderEnd = inorderEnd;

        int leftPreorderStart = preorderStart+1;
        int leftPreorderEnd = leftPreorderStart+(middleIndex-leftInorderStart);
        int rightPreorderEnd = preorderEnd;
        int rightPreorderStart = rightPreorderEnd-(rightInorderEnd-rightInorderStart);

        root.left = buildHelper(inorder,leftInorderStart,leftInorderEnd,preorder,leftPreorderStart,leftPreorderEnd);
        root.right = buildHelper(inorder,rightInorderStart,rightInorderEnd,preorder,rightPreorderStart,rightPreorderEnd);

        return root;
    }
}

代码随想录算法训练营是一个优质的学习和讨论平台,提供了丰富的算法训练内容和讨论交流机会。在训练营中,学员们可以通过观看视频讲解来学习算法知识,并根据讲解内容进行刷题练习。此外,训练营还提供了刷题建议,例如先看视频、了解自己所使用的编程语言、使用日志等方法来提高刷题效果和语言掌握程度。 训练营中的讨论内容非常丰富,涵盖了各种算法知识点和解题方法。例如,在第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 ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值