【牛客面试必刷TOP101】Day25.BM38 在二叉树中找到两个节点的最近公共祖先和BM40 重建二叉树

作者简介:大家好,我是未央;

博客首页:未央.303

系列专栏:牛客面试必刷TOP101

每日一句:人的一生,可以有所作为的时机只有一次,那就是现在!!!!!

文章目录

  • 前言
  • 一、BM38 在二叉树中找到两个节点的最近公共祖先
  • 题目描述
  • 题目解析
  • 二、BM40 重建二叉树
  • 题目描述
  • 题目解析
  • 总结


前言


一、BM38 在二叉树中找到两个节点的最近公共祖先

题目描述

描述:

给定一棵二叉树(保证非空)以及这棵树上的两个节点对应的val值 o1 和 o2,请找到 o1 和 o2 的最近公共祖先节点。



举例说明:

如当输入{3,5,1,6,2,0,8,#,#,7,4},5,1时,二叉树{3,5,1,6,2,0,8,#,#,7,4}如下图所示:

所以节点值为5和节点值为1的节点的最近公共祖先节点的节点值为3,所以对应的输出为3。

节点本身可以视为自己的祖先.


示例1:


示例2:


题目解析

方法:递归

知识点:二叉树递归

二叉树的递归,则是将某个节点的左子树、右子树看成一颗完整的树,那么对于子树的访问或者操作就是对于原树的访问或者操作的子问题,因此可以自我调用函数不断进入子树。


思路:

我们也可以讨论几种情况:

  • step 1:如果o1和o2中的任一个和root匹配,那么root就是最近公共祖先。
  • step 2:如果都不匹配,则分别递归左、右子树。
  • step 3:如果有一个节点出现在左子树,并且另一个节点出现在右子树,则root就是最近公共祖先.
  • step 4:如果两个节点都出现在左子树,则说明最低公共祖先在左子树中,否则在右子树。
  • step 5:继续递归左、右子树,直到遇到step1或者step3的情况。

 

代码解析:

import java.util.*;
public class Solution {
    //求得根节点到目标节点的路径
    public ArrayList<Integer> getPath(TreeNode root, int target) {
        //1.首先定义一个ArrayList类型的变量path,用于存储路径节点的值。
        ArrayList<Integer> path = new ArrayList<Integer>();
        //2.将根节点赋值给一个临时变量node。
        TreeNode node = root;
        //3.使用while循环,判断当前节点的值是否等于目标节点的值
        while (node.val != target) {
            path.add(node.val);
            //如果不等于,则将当前节点的值添加到path中,并根据目标节点的值与当前节点的值的大小关系,更新node为其左子节点或右子节点。
            //小的在左子树
            if (target < node.val)
                node = node.left;
            //大的在右子树
            else
                node = node.right;
        }
        //当循环结束后,将当前节点的值添加到path中。
        path.add(node.val);
        //返回path作为根节点到目标节点的路径。
        return path;
    }
    public int lowestCommonAncestor (TreeNode root, int p, int q) {
        //4.求根节点到两个节点的路径
        //在lowestCommonAncestor函数中,分别调用getPath函数,得到根节点到节点p和节点q的路径,分别保存在变量path_p和path_q中。
        ArrayList<Integer> path_p = getPath(root, p);
        ArrayList<Integer> path_q = getPath(root, q);
        //定义一个变量res,用于保存结果
        int res = 0;
        //5.比较两个路径,找到第一个不同的点
        //使用for循环,遍历path_p和path_q,比较两个路径的每个节点的值,找到第一个不同的节点.
        for (int i = 0; i < path_p.size() && i < path_q.size(); i++) {
            int x = path_p.get(i);
            int y = path_q.get(i);
            //6.最后一个相同的节点就是最近公共祖先
            if (x == y)
                res = path_p.get(i);
            else
                break;
        }
        //6.跳出循环。
        //返回res作为最近公共祖先的值。
        return res;
    }
}

二、BM40 重建二叉树

题目描述

描述:

给定节点数为 n 的二叉树的前序遍历和中序遍历结果,请重建出该二叉树并返回它的头结点。



举例说明:

例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建出如下图所示。


示例1:


示例2:

示例3:


题目解析

方法:递归

知识点:二叉树递归

二叉树的递归,则是将某个节点的左子树、右子树看成一颗完整的树,那么对于子树的访问或者操作就是对于原树的访问或者操作的子问题,因此可以自我调用函数不断进入子树。


思路:

对于二叉树的前序遍历,我们知道序列的第一个元素必定是根节点的值,因为序列没有重复的元素,因此中序遍历中可以找到相同的这个元素,而我们又知道中序遍历中根节点将二叉树分成了左右子树两个部分,如下图所示:

我们可以发现,数字1是根节点,并将二叉树分成了(247)和(3568)两棵子树,而子树的的根也是相应前序序列的首位,比如左子树的根是数字2,右子树的根是数字3,这样我们就可以利用前序遍历序列找子树的根节点,利用中序遍历序列区分每个子树的节点数。


具体做法:

  • step 1:先根据前序遍历第一个点建立根节点。
  • step 2:然后遍历中序遍历找到根节点在数组中的位置。
  • step 3:再按照子树的节点数将两个遍历的序列分割成子数组,将子数组送入函数建立子树。
  • step 4:直到子树的序列长度为0,结束递归。

代码解析:
 

import java.util.*;
public class Solution {
    //1.定义一个函数reConstructBinaryTree,用于重建二叉树。
    public TreeNode reConstructBinaryTree(int [] pre, int [] vin) {
        //该函数接收两个参数,一个是前序遍历序列pre,一个是中序遍历序列vin。
        int n = pre.length;
        int m = vin.length;
        //2.首先判断前序遍历序列和中序遍历序列的长度是否为0,如果任一序列长度为0,说明没有节点可以构建二叉树,返回null
        if (n == 0 || m == 0)
            return null;
        //3.创建根节点,节点的值为前序遍历序列的第一个值pre[0]
        TreeNode root = new TreeNode(pre[0]);
        
        for (int i = 0; i < vin.length; i++) {
        //4.然后,在中序遍历序列vin中找到前序遍历序列的第一个元素pre[0]的位置i.
            if (pre[0] == vin[i]) {
                //利用Arrays.copyOfRange方法,将前序遍历序列和中序遍历序列分别切割成左子树的前序遍历序列、左子树的中序遍历序列、右子树的前序遍历序列、右子树的中序遍历序列。
                //5.递归调用reConstructBinaryTree函数构建根节点的左子树和右子树。
                //构建左子树
                root.left = reConstructBinaryTree(Arrays.copyOfRange(pre, 1, i + 1),
                                                  Arrays.copyOfRange(vin, 0, i));
                //构建右子树
                root.right = reConstructBinaryTree(Arrays.copyOfRange(pre, i + 1, pre.length),
                                                   Arrays.copyOfRange(vin, i + 1, vin.length));
                break;
            }
        }
        //6.最后,返回根节点作为重建的二叉树的根节点
        return root;
    }
}

总结

  • 12
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
题目要求:给定一个二叉树和一个整数target,找出所有从根节点到叶子节点路径之和等于target的路径。 解题思路:可以使用深度优先搜索(DFS)的方法来解决该问题。首先定义一个辅助函数来进行递归搜索,该辅助函数的参数包括当前节点、当前路径、当前路径的和以及目标和。在搜索过程,需要维护一个数组来保存当前节点到根节点的路径。搜索过程如下: 1. 如果当前节点为空,则返回。 2. 将当前节点的值添加到当前路径。 3. 将当前节点的值累加到当前路径的和。 4. 如果当前节点是叶子节点,且当前路径的和等于目标和,则将当前路径添加到结果。 5. 递归地搜索当前节点的左子树和右子树,并传递更新后的当前路径和当前路径的和。 最后,在主函数调用辅助函数,并返回结果即可。 以下是题目的完整代码实现: ```python class TreeNode: def __init__(self, val=0, left=None, right=None): self.val = val self.left = left self.right = right def pathSum(root, target): def dfs(node, path, path_sum, target, res): if not node: return path.append(node.val) path_sum += node.val if not node.left and not node.right: # 当前节点是叶子节点 if path_sum == target: res.append(path[:]) # 注意需要复制一份path,否则会出现问题 dfs(node.left, path, path_sum, target, res) dfs(node.right, path, path_sum, target, res) path.pop() # 回溯到父节点,去掉当前节点 path_sum -= node.val res = [] dfs(root, [], 0, target, res) return res ``` 这样就能找出所有满足路径和等于目标和的路径了。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值