牛客网top101( 在二叉树中找到两个节点的最近公共结点,重建二叉树)

在二叉树中找到两个节点的最近公共结点

在这里插入图片描述
在这里插入图片描述
所以节点值为5和节点值为1的节点的最近公共祖先节点的节点值为3,所以对应的输出为3。
节点本身可以视为自己的祖先
在这里插入图片描述

解题思路:
这道题明显可以用递归进行求解,他又三种情况一种是所有的节点全都出现在左边,一种是分散在两边,最后一种是全都出现在右边。
当这棵二叉树遇到根节点为空或者是根的值等于左节点的值,或者是等于右节点的值时,这时这个根节点就是这两个节点的最近公共结点。
如果全都出现在了一边的情况,我们先判断全都出现在了哪一边。然后使用递归找到最后的公共结点。
代码如下:

    public int lowestCommonAncestor(TreeNode root, int o1, int o2) {
        return helper(root, o1, o2).val;
    }

    public TreeNode helper(TreeNode root, int o1, int o2) {
        if (root == null || root.val == o1 || root.val == o2)
            return root;
        TreeNode left = helper(root.left, o1, o2);
        TreeNode right = helper(root.right, o1, o2);
        //如果left为空,说明这两个节点在root结点的右子树上,我们只需要返回右子树查找的结果即可
        if (left == null)
            return right;
        //同上
        if (right == null)
            return left;
        //如果left和right都不为空,说明这两个节点一个在root的左子树上一个在root的右子树上,
        //我们只需要返回cur结点即可。
        return root;
    }

重建二叉树

在这里插入图片描述
在这里插入图片描述
解题思路:递归
前序遍历的第一个节点就是这颗树的根节点。

在中序遍历中,找到这个根节点,这个根节点的左边元素就是它的左子树上的元素,这个根节点的右边元素就是它的右子树上的元素。

把范围划分好,直到范围上只有一个元素直接生成返回即可。

需要找到根节点在中序遍历上的下标,才能知道它的左子树上有多少个元素,右子树上有多少个元素。为了方便找到下标,可以用 Map 结构来存储 中序遍历数组上 所有元素和其下标 的对应关系。
以下是以 前序遍历为:[8,3,6,7,9] , 中序遍历为:[3,6,8,9,7] 的演示图:
在这里插入图片描述
代码:

import java.util.*;
/**
 * Definition for binary tree
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Solution {
    public TreeNode reConstructBinaryTree(int[] pre, int[] in) {
        // 判断特殊情况
        if (pre == null || pre.length == 0 || in == null || in.length == 0) {
            return null;
        }

        // key : 中序遍历元素的值;  
        // value : 中序遍历元素的值 对应的 下标
        // 可以以O(1)的时间复杂度找到元素在中序遍历中对应的下标
        HashMap<Integer, Integer> map = new HashMap<>();
        for (int i = 0; i < in.length; i++) {
            map.put(in[i], i);
        }

        // 返回在 pre[0...pre.length-1] , in[0, in.length-1] 范围上建立二叉树的根节点
        return process(pre, 0, pre.length - 1,
                0, in.length - 1,
                map);

    }


    /**
     * @param pre 前序遍历的数组
     * @param pL  使用到的 前序遍历的数组 的左边界,闭区间
     * @param pR  使用到的 前序遍历的数组 的右边界,闭区间
     * @param inL 使用到的 中序遍历的数组 的左边界,闭区间
     * @param inR 使用到的 中序遍历的数组 的右边界,闭区间
     * @param map 方便找到元素在中序遍历中对应的下标 需要的 数据结构
     * @return 在使用到的 前序遍历数组、中序遍历数组中;生成该范围内的二叉树,返回这个二叉树的 根节点
     */
    public TreeNode process(int[] pre, int pL, int pR,
                            int inL, int inR,
                            HashMap<Integer, Integer> map) {
        // 越界情况,没有二叉树存在,直接返回 null
        if (pL > pR || inL > inR) {
            return null;
        }
        // 只有一个元素,就是根节点,直接返回
        if (pL == pR || inL == inR) {
            return new TreeNode(pre[pL]);
        }
        // 前序遍历的第一个元素就是 根节点
        TreeNode root = new TreeNode(pre[pL]);
        // 找到 根节点在 中序遍历数组里的 下标
        int inIndex = map.get(pre[pL]);
        // 在有效的中序遍历范围里, 根节点左边的元素 都是属于 根节点的左子树
        int leftTreeSize = inIndex - inL;
        // 在左子树的有效范围里,生成左子树
        root.left = process(pre, pL + 1, pL + leftTreeSize,
                inL, inIndex - 1,
                map);
        // 在右子树的有效范围里,生成右子树
        root.right = process(pre, pL + leftTreeSize + 1, pR,
                inIndex + 1, inR,
                map);
        return root;
    } 

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值