在二叉树中找到两个节点的最近公共结点
所以节点值为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;
}
}