LeetCode刷题Day15——二叉树(树左下角的值、路径和、树的构造、最大二叉树、合并二叉树)

简介: 一、找树左下角的值题目链接:513. 找树左下角的值

一、找树左下角的值

题目链接:513. 找树左下角的值

/**
 * <pre>
 * 1.广搜,每一层遍历,找到最左边的节点记录下值
 * 2.深搜,找到最深的一层就将结果记录下来,先遍历的是左节点,所以右节点如果同样高度则不会覆盖掉左节点的值,保证了最终找到的是最左边的节点
 * </pre>
 *
 * @author <a href="https://github.com/Ken-Chy129">Ken-Chy129</a>
 * @date 2023/1/16 13:44
 */
public class 找树左下角的值513 {
    public int findBottomLeftValue(TreeNode root) {
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        int ans = root.val;
        boolean flag = true; // 此处也可以不使用flag,而是每次offer入队的时候先入right节点,那么最后一次poll出来的节点就是当层最左边的节点
        while (!queue.isEmpty()) {
            int size = queue.size();
            for (int i=0; i<size; i++) {
                TreeNode poll = queue.poll();
                if (poll.left != null) {
                    queue.offer(poll.left);
                    if (flag) {
                        ans = poll.left.val;
                        flag = false;
                    }
                }
                if (poll.right != null) {
                    queue.offer(poll.right);
                    if (flag) {
                        ans = poll.right.val;
                        flag = false;
                    }
                }
            }
            flag = true;
        }
        return ans;
    }
    int res = 0;
    int maxHeight = -1;
    public int findBottomLeftValue2(TreeNode root) {
        dfs(root, 0);
        return res;
    }
    public void dfs(TreeNode root, int height) {
        if (root.left == null && root.right == null) {
            if (height > maxHeight) {
                maxHeight = height;
                res = root.val;
            }
            return;
        }
        if (root.left != null) {
            dfs(root.left, height+1);
        }
        if (root.right != null) {
            dfs(root.right, height+1);
        }
    }
}

二、路径总和

题目链接:112. 路径总和

/**
 * <pre>
 * 1.深搜
 * 2.广搜
 * 节点的值有可能是负数,所以不能大于targetSum就剪枝
 * </pre>
 *
 * @author <a href="https://github.com/Ken-Chy129">Ken-Chy129</a>
 * @date 2023/1/16 15:19
 */
public class 路径总和112 {
    public boolean hasPathSum(TreeNode root, int targetSum) {
        if (root == null) {
            return false;
        }
        return dfs(root, targetSum, root.val);
    }
    public boolean dfs(TreeNode root, int targetSum, int nowSum) {
        if (root.left == null && root.right == null) {
            return nowSum == targetSum;
        }
        boolean rs1=false, rs2=false;
        if (root.left != null) {
            rs1 = dfs(root.left, targetSum, nowSum+root.left.val);
        }
        if (root.right != null) {
            rs2 = dfs(root.right, targetSum, nowSum+root.right.val);
        }
        return rs1 || rs2;
    }
    public boolean hasPathSum2(TreeNode root, int targetSum) {
        if (root == null) {
            return false;
        }
        Queue<TreeNode> nodeQueue = new LinkedList<>();
        Queue<Integer> sumQueue = new LinkedList<>();
        nodeQueue.offer(root);
        sumQueue.offer(root.val);
        while (!nodeQueue.isEmpty()) {
            int size = nodeQueue.size();
            for (int i=0; i<size; i++) {
                TreeNode node = nodeQueue.poll();
                Integer sum = sumQueue.poll();
                if (node.left == null && node.right == null) {
                    if (sum == targetSum) {
                        return true;
                    }
                }
                if (node.left != null) {
                    nodeQueue.offer(node.left);
                    sumQueue.offer(sum+node.left.val);
                }
                if (node.right != null) {
                    nodeQueue.offer(node.right);
                    sumQueue.offer(sum+node.right.val);
                }
            }
        }
        return false;
    }
}

三、从前序与中序遍历序列构造二叉树

题目链接:105. 从前序与中序遍历序列构造二叉树

/**
 * <pre>
 * 递归:从前往后依次取出前缀遍历数组的值,以其作为分割点,不断将中序数组分割为左右子树
 * </pre>
 *
 * @author <a href="https://github.com/Ken-Chy129">Ken-Chy129</a>
 * @date 2023/1/16 17:24
 */
public class 从前序与中序遍历序列构造二叉树105 {
    int pre_idx = 0;
    int[] preorder;
    int[] inorder;
    Map<Integer, Integer> idx_map = new HashMap<>();
    public TreeNode buildTree(int[] preorder, int[] inorder) {
        this.preorder = preorder;
        this.inorder = inorder;
        int index = 0;
        for (int val : inorder) {
            idx_map.put(val, index++);
        }
        return build(0, inorder.length-1);
    }
    public TreeNode build(int in_left, int in_right) {
        if (in_left > in_right) {
            return null;
        }
        int val = preorder[pre_idx++];
        TreeNode root = new TreeNode(val);
        Integer index = idx_map.get(val);
        root.left = build(in_left, index-1);
        root.right = build(index+1, in_right);
        return root;
    }
}

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

题目链接:106.从中序与后序遍历序列构造二叉树

/**
 * <pre>
 * 递归:从后往前依次取出前缀遍历数组的值,以其作为分割点,不断将中序数组分割为右左子树
 * </pre>
 *
 * @author <a href="https://github.com/Ken-Chy129">Ken-Chy129</a>
 * @date 2023/1/16 16:21
 */
public class 从中序与后序遍历序列构造二叉树106 {
    int post_idx;
    int[] postorder;
    int[] inorder;
    Map<Integer, Integer> idx_map = new HashMap<>();
    public TreeNode buildTree(int[] inorder, int[] postorder) {
        this.inorder = inorder;
        this.postorder = postorder;
        post_idx = postorder.length - 1;
        int index = 0;
        for (int val : inorder) {
            idx_map.put(val, index++);
        }
        return build(0, inorder.length-1);
    }
    public TreeNode build(int in_left, int in_right) {
        // 如果这里没有节点构造二叉树了,就结束
        if (in_left > in_right) {
            return null;
        }
        // 选择 post_idx 位置的元素作为当前子树根节点
        int root_val = postorder[post_idx];
        TreeNode root = new TreeNode(root_val);
        // 根据 root 所在位置分成左右两棵子树
        int index = idx_map.get(root_val);
        // 下标减一
        post_idx--;
        // 先构造右子树,因为从后取后序遍历数组的值,去完根节点后接着最开始取到的就是最右边的节点
        root.right = build(index + 1, in_right);
        // 构造左子树
        root.left = build(in_left, index - 1);
        return root;
    }
}

五、最大二叉树

题目链接:654. 最大二叉树

/**
 * <pre>
 * 递归
 * 单调栈
 * </pre>
 *
 * @author <a href="https://github.com/Ken-Chy129">Ken-Chy129</a>
 * @date 2023/1/17 11:45
 */
public class 最大二叉树654 {
    public TreeNode constructMaximumBinaryTree(int[] nums) {
        if (nums.length == 0) {
            return null;
        }
        TreeNode root = new TreeNode();
        int max = nums[0], index=0;
        for (int i=1; i<nums.length; i++) {
            if (nums[i] > max) {
                index = i;
                max = nums[i];
            }
        }
        root.val = max;
        root.left = constructMaximumBinaryTree(Arrays.copyOfRange(nums, 0, index));
        root.right = constructMaximumBinaryTree(Arrays.copyOfRange(nums, index+1, nums.length));
        return root;
    }
}

六、合并二叉树

题目链接:617. 合并二叉树

/**
 * <pre>
 * 1.深搜
 * 2.广搜
 * </pre>
 *
 * @author <a href="https://github.com/Ken-Chy129">Ken-Chy129</a>
 * @date 2023/1/17 12:23
 */
public class 合并二叉树617 {
    public TreeNode mergeTrees(TreeNode root1, TreeNode root2) {
        if (root1 == null) {
            return root2;
        }
        if (root2 == null) {
            return root1;
        }
        TreeNode merged = new TreeNode(root1.val + root2.val);
        merged.left = mergeTrees(root1.left, root2.left);
        merged.right = mergeTrees(root1.right, root2.right);
        return merged;
    }
    public TreeNode mergeTrees2(TreeNode root1, TreeNode root2) {
        if (root1 == null) {
            return root2;
        }
        if (root2 == null) {
            return root1;
        }
        Queue<TreeNode> treeQueue1 = new LinkedList<>();
        Queue<TreeNode> treeQueue2 = new LinkedList<>();
        Queue<TreeNode> mergedQueue = new LinkedList<>();
        treeQueue1.offer(root1);
        treeQueue2.offer(root2);
        TreeNode ans = new TreeNode(root1.val + root2.val);
        mergedQueue.offer(ans);
        while (!treeQueue1.isEmpty() || !treeQueue2.isEmpty()) {
            TreeNode treeNode1 = treeQueue1.poll();
            TreeNode treeNode2 = treeQueue2.poll();
            TreeNode root = mergedQueue.poll();
            TreeNode mergedNode1, mergedNode2;
            if (treeNode1.left == null) {
                mergedNode1 = treeNode2.left;
            } else if (treeNode2.left == null) {
                mergedNode1 = treeNode1.left;
            } else {
                treeQueue1.offer(treeNode1.left);
                treeQueue2.offer(treeNode2.left);
                mergedNode1 = new TreeNode(treeNode1.left.val + treeNode2.left.val);
                mergedQueue.offer(mergedNode1);
            }
            root.left = mergedNode1;
            if (treeNode1.right == null) {
                mergedNode2 = treeNode2.right;
            } else if (treeNode2.right == null) {
                mergedNode2 = treeNode1.right;
            } else {
                treeQueue1.offer(treeNode1.right);
                treeQueue2.offer(treeNode2.right);
                mergedNode2 = new TreeNode(treeNode1.right.val + treeNode2.right.val);
                mergedQueue.offer(mergedNode2);
            }
            root.right = mergedNode2;
        }
        return ans;
    }
}
相关文章
|
Go 开发者 索引
【LeetCode 热题100】路径与祖先:二叉树中的深度追踪技巧(力扣33 / 81/ 153/154)(Go语言版)
本文深入探讨了LeetCode中四道关于「搜索旋转排序数组」的经典题目,涵盖了无重复和有重复元素的情况。通过二分查找的变形应用,文章详细解析了每道题的解题思路和Go语言实现代码。关键点包括判断有序区间、处理重复元素以及如何缩小搜索范围。文章还总结了各题的异同,并推荐了类似题目,帮助读者全面掌握二分查找在旋转数组中的应用。无论是初学者还是有经验的开发者,都能从中获得实用的解题技巧和代码实现方法。
560 14
|
算法 Go
【LeetCode 热题100】深入理解二叉树结构变化与路径特性(力扣104 / 226 / 114 / 543)(Go语言版)
本博客深入探讨二叉树的深度计算、结构变换与路径分析,涵盖四道经典题目:104(最大深度)、226(翻转二叉树)、114(展开为链表)和543(二叉树直径)。通过递归与遍历策略(前序、后序等),解析每题的核心思路与实现方法。结合代码示例(Go语言),帮助读者掌握二叉树相关算法的精髓。下一讲将聚焦二叉树构造问题,欢迎持续关注!
433 10
|
Go 索引 Perl
【LeetCode 热题100】【二叉树构造题精讲:前序 + 中序建树 & 有序数组构造 BST】(详细解析)(Go语言版)
本文详细解析了二叉树构造的两类经典问题:通过前序与中序遍历重建二叉树(LeetCode 105),以及将有序数组转化为平衡二叉搜索树(BST,LeetCode 108)。文章从核心思路、递归解法到实现细节逐一拆解,强调通过索引控制子树范围以优化性能,并对比两题的不同构造逻辑。最后总结通用构造套路,提供进阶思考方向,帮助彻底掌握二叉树构造类题目。
977 9
|
Go
【LeetCode 热题100】路径与祖先:二叉树中的深度追踪技巧(力扣437 / 236 )(Go语言版)
本文深入探讨二叉树中路径与祖先问题,涵盖两道经典题目:LeetCode 437(路径总和 III)和236(最近公共祖先)。对于路径总和 III,文章分析了双递归暴力解法与前缀和优化方法,后者通过哈希表记录路径和,将时间复杂度从O(n²)降至O(n)。在最近公共祖先问题中,采用后序遍历递归查找,利用“自底向上”的思路确定最近公共祖先节点。文中详细解析代码实现与核心要点,帮助读者掌握深度追踪技巧,理解树结构中路径与节点关系的本质。这类问题在面试中高频出现,掌握其解法意义重大。
349 4
|
Unix Shell Linux
LeetCode刷题 Shell编程四则 | 194. 转置文件 192. 统计词频 193. 有效电话号码 195. 第十行
本文提供了几个Linux shell脚本编程问题的解决方案,包括转置文件内容、统计词频、验证有效电话号码和提取文件的第十行,每个问题都给出了至少一种实现方法。
468 6
LeetCode刷题 Shell编程四则 | 194. 转置文件 192. 统计词频 193. 有效电话号码 195. 第十行
|
Python
【Leetcode刷题Python】剑指 Offer 32 - III. 从上到下打印二叉树 III
本文介绍了两种Python实现方法,用于按照之字形顺序打印二叉树的层次遍历结果,实现了在奇数层正序、偶数层反序打印节点的功能。
244 6
|
搜索推荐 索引 Python
【Leetcode刷题Python】牛客. 数组中未出现的最小正整数
本文介绍了牛客网题目"数组中未出现的最小正整数"的解法,提供了一种满足O(n)时间复杂度和O(1)空间复杂度要求的原地排序算法,并给出了Python实现代码。
564 2
|
数据采集 负载均衡 安全
LeetCode刷题 多线程编程九则 | 1188. 设计有限阻塞队列 1242. 多线程网页爬虫 1279. 红绿灯路口
本文提供了多个多线程编程问题的解决方案,包括设计有限阻塞队列、多线程网页爬虫、红绿灯路口等,每个问题都给出了至少一种实现方法,涵盖了互斥锁、条件变量、信号量等线程同步机制的使用。
472 4
LeetCode刷题 多线程编程九则 | 1188. 设计有限阻塞队列 1242. 多线程网页爬虫 1279. 红绿灯路口
|
机器学习/深度学习 人工智能 自然语言处理
280页PDF,全方位评估OpenAI o1,Leetcode刷题准确率竟这么高
【10月更文挑战第24天】近年来,OpenAI的o1模型在大型语言模型(LLMs)中脱颖而出,展现出卓越的推理能力和知识整合能力。基于Transformer架构,o1模型采用了链式思维和强化学习等先进技术,显著提升了其在编程竞赛、医学影像报告生成、数学问题解决、自然语言推理和芯片设计等领域的表现。本文将全面评估o1模型的性能及其对AI研究和应用的潜在影响。
504 1
|
索引 Python
【Leetcode刷题Python】从列表list中创建一颗二叉树
本文介绍了如何使用Python递归函数从列表中创建二叉树,其中每个节点的左右子节点索引分别是当前节点索引的2倍加1和2倍加2。
592 7

热门文章

最新文章