[剑指 Offer 第 2 版第 7 题] “重建二叉树”做题记录
- 牛客网 online judge 地址:https://www.nowcoder.com/practice/8a19cbe657394eeaac2f6ea9b0f6fcf6?tpId=13&tqId=11157&tPage=1&rp=2&ru=%2Fta%2Fcoding-interviews&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking
题目描述
输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。
求解思路与关键
- 画图是解决这一类问题的关键,千万不要犯懒,拿出纸和笔,动手操作一下,往往思路就很清晰了。
- 用类似二叉树插入节点的方式建立二叉树,即使用递归函数,返回新创建二叉树根节点的方式,将新的二叉树的根结点挂接到原来的二叉树的左右结点中。
- 前序遍历的第 1 个元素就是二叉树的根结点。根据这一点,不难写出递归函数的代码。注意这是以“输入的前序遍历和中序遍历的结果中都不含重复的数字”为前提的。
参考解答
参考解答1
class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int x) {
val = x;
}
}
public class Solution {
public TreeNode reConstructBinaryTree(int[] pre, int[] in) {
TreeNode root = reConstructBinaryTree(pre, 0, pre.length - 1, in, 0, in.length - 1);
return root;
}
/**
* 根据前序遍历数组的 [preL, preR] 和 中序遍历数组的 [inL, inR] 重新组建二叉树
*
* @param pre 前序遍历数组
* @param preL 前序遍历数组的区间左端点
* @param preR 前序遍历数组的区间右端点
* @param in 中序遍历数组
* @param inL 中序遍历数组的区间左端点
* @param inR 中序遍历数组的区间右端点
* @return 构建的新二叉树的根结点
*/
private TreeNode reConstructBinaryTree(int[] pre, int preL, int preR, int[] in, int inL, int inR) {
if (preL > preR || inL > inR) {
return null;
}
// 构建的新二叉树的根结点一定是前序遍历数组的第 1 个元素
TreeNode root = new TreeNode(pre[preL]);
// 从中序遍历的左区间端点开始找,找到和前序遍历数组的第 1 个元素的值相等的节点
int i = inL;
while (in[i] != pre[preL] && i <= inR) {
i++;
}
// 在中序遍历数组中遍历了几个元素: i - inL
// 接下来就是递归调用,关键的地方在于找前序遍历数组和中序遍历数组对应的区间的端点
root.left = reConstructBinaryTree(pre, preL + 1, preL + (i - inL), in, inL, i - 1);
root.right = reConstructBinaryTree(pre, preL + (i - inL) + 1, preR, in, i + 1, inR);
return root;
}
}