当前位置: 首页 > news >正文

leetcode二叉树3

404.左叶子之和

给定二叉树的根节点 root ,返回所有左叶子之和。

示例 1:

输入: root = [3,9,20,null,null,15,7] 
输出: 24 
解释: 在这个二叉树中,有两个左叶子,分别是 9 和 15,所以返回 24

示例 2:

输入: root = [1]
输出: 0

提示:

  • 节点数在 [1, 1000] 范围内
  • -1000 <= Node.val <= 1000

解题思路

通过递归遍历二叉树,识别并累加所有左叶子节点的值。使用一个标志变量 flag 区分当前节点是否为其父节点的左子节点,只有当节点是叶子节点且是左子节点时,才将其值加到全局变量 sum 中。主函数从根节点开始递归,特殊处理单节点树(根节点不算左叶子),最终返回总和。

代码 

class Solution {
    int sum = 0; // 定义全局变量,用于累加所有左叶子节点的值
    
    // 辅助函数:递归遍历二叉树,计算左叶子之和
    // root: 当前处理的节点
    // flag: 标记当前节点是左子节点(1)还是右子节点(0)
    public void fun1(TreeNode root, int flag) {
        // 如果当前节点是叶子节点(无左子节点且无右子节点)
        if (root.left == null && root.right == null) { 
            // 检查是否是左叶子节点,只有 flag 为 1 时才累加
            if (flag == 1) {
                sum += root.val; // 将左叶子节点的值加到 sum 中
            }
        } else { // 如果不是叶子节点,继续递归处理子节点
            // 如果存在左子节点,递归调用并标记为左子节点 (flag=1)
            if (root.left != null) fun1(root.left, 1);
            // 如果存在右子节点,递归调用并标记为右子节点 (flag=0)
            if (root.right != null) fun1(root.right, 0);
        }
    }
    
    // 主函数:返回二叉树所有左叶子之和
    public int sumOfLeftLeaves(TreeNode root) {
        // 特殊情况:如果树只有一个节点(根节点是叶子),返回 0
        if (root.left == null && root.right == null) {
            return 0; // 根节点本身不算左叶子
        }
        fun1(root, 0); // 从根节点开始递归,根节点初始标记为 0(非左子节点)
        return sum; // 返回累加的结果
    }
}

513.找树左下角的值

给定一个二叉树的 根节点 root,请找出该二叉树的 最底层 最左边 节点的值。

假设二叉树中至少有一个节点。

示例 1:

输入: root = [2,1,3]
输出: 1

示例 2:

输入: [1,2,3,4,null,5,6,null,null,7]
输出: 7

提示:

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

 

解题思路

通过层次遍历(BFS,广度优先搜索)找到二叉树的最底层,并记录每一层的最左节点值。由于层次遍历从左到右访问节点,每层的第一个节点即为最左节点,而最后一层的第一个节点即为最底层的最左节点。使用队列存储每层节点,遍历完所有层后,ans 保存的就是目标值。

代码 

class Solution {
    public int findBottomLeftValue(TreeNode root) {
        int ans = root.val; // 初始化答案为根节点的值,作为最底层最左节点的候选
        Queue<TreeNode> queue = new ArrayDeque<>(); // 创建队列,用于层次遍历
        queue.offer(root); // 将根节点加入队列,开始遍历
        
        // 当队列不为空时,继续层次遍历
        while (!queue.isEmpty()) {
            boolean flag = true; // 标志位,用于标记每层的最左节点
            int size = queue.size(); // 获取当前层的节点数
            
            // 遍历当前层的所有节点
            while (size-- > 0) {
                TreeNode node = new TreeNode(); // 创建一个临时节点对象(稍显冗余)
                node = queue.poll(); // 从队列中取出当前节点,覆盖临时对象
                if (flag) ans = node.val; // 如果是该层第一个节点,更新答案为当前节点值
                flag = false; // 标志位置为 false,确保只记录最左节点
                
                // 将左子节点加入队列(如果存在)
                if (node.left != null) queue.offer(node.left);
                // 将右子节点加入队列(如果存在)
                if (node.right != null) queue.offer(node.right);
            }
        }
        return ans; // 返回最底层最左节点的值
    }
}

112.路径总和

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

叶子节点 是指没有子节点的节点。

示例 1:

输入:root = [5,4,8,11,null,13,4,7,2,null,null,null,1], targetSum = 22
输出:true
解释:等于目标和的根节点到叶节点路径如上图所示。

示例 2:

输入:root = [1,2,3], targetSum = 5
输出:false
解释:树中存在两条根节点到叶子节点的路径:
(1 --> 2): 和为 3
(1 --> 3): 和为 4
不存在 sum = 5 的根节点到叶子节点的路径。

示例 3:

输入:root = [], targetSum = 0
输出:false
解释:由于树是空的,所以不存在根节点到叶子节点的路径。

提示:

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

解题思路

通过深度优先搜索(DFS)递归遍历二叉树,从根节点到每个叶子节点计算路径和。每次递归时累加当前节点值,并在到达叶子节点时检查路径和是否等于目标值 targetSum。如果存在至少一条路径满足条件,则返回 true,否则返回 false。主函数处理空树情况,并启动递归过程。

代码 

class Solution {
    // 辅助函数:递归检查是否存在从当前节点到叶子节点的路径和等于目标值
    // root: 当前处理的节点
    // sum: 从根节点到当前节点的路径和
    // targetSum: 目标和
    public boolean fun1(TreeNode root, int sum, int targetSum) {
        // 如果当前节点为空,返回 false(空路径不满足条件)
        if (root == null) {
            return false;
        }
        
        // 将当前节点值加到路径和中
        sum += root.val;
        
        // 如果当前节点是叶子节点(无左子节点且无右子节点)
        if (root.left == null && root.right == null) {
            // 检查路径和是否等于目标和,若相等返回 true
            if (sum == targetSum) return true;
        }
        
        // 递归检查左子树或右子树是否存在满足条件的路径
        // 使用 || 表示只要有一条路径满足条件即返回 true
        return fun1(root.left, sum, targetSum) || fun1(root.right, sum, targetSum);
    }

    // 主函数:判断是否存在从根节点到叶子节点的路径和等于目标值
    public boolean hasPathSum(TreeNode root, int targetSum) {
        // 特殊情况:如果树为空,返回 false
        if (root == null) {
            return false;
        }
        
        // 调用辅助函数,从根节点开始,初始路径和为 0
        return fun1(root, 0, targetSum);
    }
}

113.路径总和II

给你二叉树的根节点 root 和一个整数目标和 targetSum ,找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。

叶子节点 是指没有子节点的节点。

示例 1:

输入:root = [5,4,8,11,null,13,4,7,2,null,null,5,1], targetSum = 22
输出:[[5,4,11,2],[5,8,4,5]]

示例 2:

输入:root = [1,2,3], targetSum = 5
输出:[]

示例 3:

输入:root = [1,2], targetSum = 0
输出:[]

提示:

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

解题思路

通过深度优先搜索(DFS)递归遍历二叉树,从根节点到每个叶子节点,记录路径并计算路径和。使用一个临时列表 list 保存当前路径,在到达叶子节点时检查路径和是否等于目标值 targetSum,若满足则将路径副本加入结果集 ans。通过回溯(移除当前节点值)确保路径记录的正确性,最终返回所有满足条件的路径。

代码 

class Solution {
    // 定义全局变量,用于存储所有满足条件的路径
    List<List<Integer>> ans = new ArrayList<>();
    
    // 辅助函数:递归遍历二叉树,寻找从根到叶子路径和等于目标值的路径
    // root: 当前处理的节点
    // sum: 从根节点到当前节点的路径和
    // targetSum: 目标和
    // list: 当前路径的临时记录
    public void fun1(TreeNode root, int sum, int targetSum, ArrayList list) {
        // 如果当前节点为空,直接返回(空路径不处理)
        if (root == null) {
            return;
        }
        
        // 将当前节点值加入临时路径
        list.add(root.val);
        // 更新路径和
        sum += root.val;
        
        // 如果当前节点是叶子节点(无左子节点且无右子节点)
        if (root.left == null && root.right == null) {
            // 检查路径和是否等于目标和
            if (sum == targetSum) {
                // 如果满足条件,将当前路径的副本加入结果集
                ans.add(new ArrayList<>(list));
            }
        } else {
            // 如果不是叶子节点,继续递归遍历左子树
            fun1(root.left, sum, targetSum, list);
            // 递归遍历右子树
            fun1(root.right, sum, targetSum, list);
        }
        
        // 回溯:移除当前节点值,以便尝试其他路径
        list.remove(list.size() - 1);
    }

    // 主函数:返回所有从根到叶子路径和等于目标值的路径
    public List<List<Integer>> pathSum(TreeNode root, int targetSum) {
        // 创建临时列表,用于记录当前路径
        ArrayList<Integer> list = new ArrayList<>();
        // 调用辅助函数开始递归
        fun1(root, 0, targetSum, list);
        // 返回结果集
        return ans;
    }
}

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

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

示例 1:

输入:inorder = [9,3,15,20,7], postorder = [9,15,7,20,3]
输出:[3,9,20,null,null,15,7]

示例 2:

输入:inorder = [-1], postorder = [-1]
输出:[-1]

提示:

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

解题思路

利用后序遍历的最后一个元素作为根节点,通过中序遍历找到根节点的左右子树范围,递归构建二叉树。为了避免每次线性查找根节点在中序遍历中的位置,使用哈希表预先存储值到索引的映射,从而将查找时间从 O(n) 优化到 O(1)。通过递归划分数组范围,最终构造出完整的二叉树。

代码

class Solution {
    // 定义哈希表,用于快速查找中序遍历中值的索引
    private HashMap<Integer, Integer> inorderMap;
    
    // 辅助函数:根据中序和后序遍历递归构建二叉树
    // inorder: 中序遍历数组
    // postorder: 后序遍历数组
    // inStart, inEnd: 中序遍历的当前范围
    // postStart, postEnd: 后序遍历的当前范围
    private TreeNode buildTreeHelper(int[] inorder, int[] postorder, 
                                    int inStart, int inEnd, 
                                    int postStart, int postEnd) {
        // 如果当前范围无效,返回 null(无子树)
        if (inStart > inEnd) {
            return null;
        }
        
        // 后序遍历的最后一个元素是当前子树的根节点
        int rootVal = postorder[postEnd];
        TreeNode root = new TreeNode(rootVal);
        
        // 在中序遍历中找到根节点的索引
        int rootIndex = inorderMap.get(rootVal);
        
        // 计算左子树的节点数
        int leftSize = rootIndex - inStart;
        
        // 递归构建左子树
        root.left = buildTreeHelper(inorder, postorder, 
                                   inStart, rootIndex - 1, 
                                   postStart, postStart + leftSize - 1);
        
        // 递归构建右子树
        root.right = buildTreeHelper(inorder, postorder, 
                                    rootIndex + 1, inEnd, 
                                    postStart + leftSize, postEnd - 1);
        
        return root;
    }
    
    // 主函数:根据中序和后序遍历构造二叉树
    public TreeNode buildTree(int[] inorder, int[] postorder) {
        // 初始化哈希表,存储中序遍历值到索引的映射
        inorderMap = new HashMap<>();
        for (int i = 0; i < inorder.length; i++) {
            inorderMap.put(inorder[i], i);
        }
        
        // 调用辅助函数,初始范围为整个数组
        return buildTreeHelper(inorder, postorder, 
                              0, inorder.length - 1, 
                              0, postorder.length - 1);
    }
}

// TreeNode 定义(假设已提供)
class TreeNode {
    int val;
    TreeNode left;
    TreeNode right;
    TreeNode(int val) {
        this.val = val;
    }
}

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

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

示例 1:

输入: preorder = [3,9,20,15,7], inorder = [9,3,15,20,7]
输出: [3,9,20,null,null,15,7]

示例 2:

输入: preorder = [-1], inorder = [-1]
输出: [-1]

提示:

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

 

解题思路

利用前序遍历的第一个元素作为根节点,通过中序遍历找到根节点的左右子树范围,递归构建二叉树。为了避免每次线性查找根节点在中序遍历中的位置,使用哈希表预先存储值到索引的映射,从而将查找时间从 O(n) 优化到 O(1)。通过递归划分数组范围,最终构造出完整的二叉树。

代码 

class Solution {
    // 定义哈希表,用于快速查找中序遍历中值的索引
    private HashMap<Integer, Integer> inorderMap;

    // 辅助函数:根据前序和中序遍历递归构建二叉树
    // inorder: 中序遍历数组
    // preorder: 前序遍历数组
    // inStart, inEnd: 中序遍历的当前范围
    // preStart, preEnd: 前序遍历的当前范围
    public TreeNode fun1(int[] inorder, int[] preorder, int inStart, int inEnd, int preStart, int preEnd) {
        // 如果当前范围无效(中序或前序范围不合法),返回 null
        if (inEnd < inStart || preStart > preEnd) return null;

        // 前序遍历的第一个元素是当前子树的根节点
        TreeNode root = new TreeNode(preorder[preStart]);
        
        // 在中序遍历中找到根节点的索引(使用哈希表快速查找)
        int mid = inorderMap.get(root.val);
        
        // 计算左子树的节点数
        int leftSize = mid - inStart;

        // 递归构建左子树
        // 左子树的中序范围: [inStart, mid - 1]
        // 左子树的前序范围: [preStart + 1, preStart + leftSize]
        root.left = fun1(inorder, preorder, inStart, mid - 1, preStart + 1, preStart + leftSize);
        
        // 递归构建右子树
        // 右子树的中序范围: [mid + 1, inEnd]
        // 右子树的前序范围: [preStart + leftSize + 1, preEnd]
        root.right = fun1(inorder, preorder, mid + 1, inEnd, preStart + leftSize + 1, preEnd);

        // 返回当前子树的根节点
        return root;
    }

    // 主函数:根据前序和中序遍历构造二叉树
    public TreeNode buildTree(int[] preorder, int[] inorder) {
        // 如果输入数组为空或长度为 0,返回 null
        if (inorder == null || inorder.length == 0) return null;

        // 初始化哈希表,存储中序遍历值到索引的映射
        inorderMap = new HashMap<>();
        for (int i = 0; i < inorder.length; i++) {
            inorderMap.put(inorder[i], i);
        }

        // 调用辅助函数,初始范围为整个数组
        return fun1(inorder, preorder, 0, inorder.length - 1, 0, preorder.length - 1);
    }
}

// TreeNode 定义(假设已提供)
class TreeNode {
    int val;
    TreeNode left;
    TreeNode right;
    TreeNode(int val) {
        this.val = val;
    }
}

 654.最大二叉树

给定一个不重复的整数数组 nums 。 最大二叉树 可以用下面的算法从 nums 递归地构建:

  1. 创建一个根节点,其值为 nums 中的最大值。
  2. 递归地在最大值 左边 的 子数组前缀上 构建左子树。
  3. 递归地在最大值 右边 的 子数组后缀上 构建右子树。

返回 nums 构建的 最大二叉树 

示例 1:

输入:nums = [3,2,1,6,0,5]
输出:[6,3,5,null,2,0,null,null,1]
解释:递归调用如下所示:
- [3,2,1,6,0,5] 中的最大值是 6 ,左边部分是 [3,2,1] ,右边部分是 [0,5] 。
    - [3,2,1] 中的最大值是 3 ,左边部分是 [] ,右边部分是 [2,1] 。
        - 空数组,无子节点。
        - [2,1] 中的最大值是 2 ,左边部分是 [] ,右边部分是 [1] 。
            - 空数组,无子节点。
            - 只有一个元素,所以子节点是一个值为 1 的节点。
    - [0,5] 中的最大值是 5 ,左边部分是 [0] ,右边部分是 [] 。
        - 只有一个元素,所以子节点是一个值为 0 的节点。
        - 空数组,无子节点。

示例 2:

输入:nums = [3,2,1]
输出:[3,null,2,null,1]

提示:

  • 1 <= nums.length <= 1000
  • 0 <= nums[i] <= 1000
  • nums 中的所有整数 互不相同

解题思路

通过递归分治的方式构建最大二叉树。每次在当前子数组范围内找到最大值作为根节点,然后将数组分为左子数组和右子数组,分别递归构建左子树和右子树。使用索引范围控制递归,确保正确划分子树,最终返回构造好的二叉树根节点。

代码 

class Solution {
    // 辅助函数:递归构建最大二叉树
    // nums: 输入的整数数组
    // start: 当前子数组的起始索引
    // end: 当前子数组的结束索引
    public TreeNode fun1(int[] nums, int start, int end) {
        // 如果当前范围无效(起始索引大于结束索引),返回 null
        if (start > end) return null;
        
        // 创建当前子树的根节点
        TreeNode root = new TreeNode();
        int max = 0;    // 记录当前范围内的最大值
        int index = 0;  // 记录最大值的索引
        
        // 遍历当前范围,找到最大值及其索引
        for (int i = start; i <= end; i++) {
            if (max <= nums[i]) { // 使用 <= 确保更新到最后一个最大值
                index = i;        // 更新最大值索引
                max = nums[i];    // 更新最大值
            }
        }
        
        // 设置根节点值为最大值
        root.val = max;
        
        // 递归构建左子树(最大值左边的子数组)
        root.left = fun1(nums, start, index - 1);
        
        // 递归构建右子树(最大值右边的子数组)
        root.right = fun1(nums, index + 1, end);
        
        // 返回当前子树的根节点
        return root;
    }
    
    // 主函数:根据数组构造最大二叉树
    public TreeNode constructMaximumBinaryTree(int[] nums) {
        // 特殊情况:如果数组长度为 1,直接返回单节点树
        if (nums.length == 1) return new TreeNode(nums[0]);
        
        // 调用辅助函数,初始范围为整个数组
        return fun1(nums, 0, nums.length - 1);
    }
}

相关文章:

  • thinkphp漏洞再现
  • Anaconda 安装NCL (Linux系统)
  • GithubPages+自定义域名+Cloudfare加速+浏览器收录(2025最新排坑)
  • [免费]SpringBoot+Vue扶贫管理系统【论文+源码+SQL脚本】
  • Unity3D 动态遮挡剔除(Occlusion Culling)
  • 基于Spring Boot的智能停车计费系统的设计与实现(LW+源码+讲解)
  • 针对 WebView 强制使用本地字体的完整解决方案
  • windows docker如何修改 默认的Container memory usage
  • 2025-如何创建自己的电商网站
  • cfca 申请国密证书流程
  • Aider的Repo Map功能
  • 跨域问题的解决方案
  • 基于MATLAB的涡旋光和高斯光叠加产生平顶光
  • 深入解析 TCP:可靠传输的基石
  • YAML是什么?
  • 借助Trae从零开始完成贪吃蛇的项目
  • 解决 Element UI 嵌套弹窗显示灰色的问题!!!
  • LeetCode 解题思路 24(Hot 100)
  • 清华大学第12弹:《DeepSeek政务应用场景与解决方案》.pdf(文末附免费下载地址)
  • git_version_control_proper_practice
  • 郑州政府网站建设/seo关键词布局案例
  • 校园网网站建设/网页制作html代码
  • 有哪些做短租的网站好/如何进行搜索引擎优化?