剑指Offer之重建二叉树
题目描述
输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。
分析:
在二叉树的前序遍历中,第一个数字总是树的根节点的值。但在中序遍历序列中,根节点的值在序列的中间,左子树的值位于根节点的左边,而右子树的节点的值位于根节点的值得右边。因此我们需要扫描中序遍历,才能找到根节点的值。
如下图所示,前序遍历序列的第一个数字1就是根节点的值。扫描中序遍历序列,就能确定根节点的值得位置。根据中序遍历特点,在根节点的值1前面的3个数字都是左子树节点的值,位于1后面的数字都是右子树节点的值。
由于在中序遍历中,有3个数字是左子树节点的值,因此左子树总共有3个左子节点。同样,在前序遍历中,根节点后面的3个数字就是3个左子树节点的值,再后面的所有数字都是右节点的值。这样我们就在前序遍历和中序遍历两个序列中,分别找到了左右子树对应的子序列。
Java代码
1 import java.util.LinkedList;
2 import java.util.Queue;
3 import java.util.Scanner;
4
5 /**
6 * Created by Feng on 2017/5/1.
7 * 输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
8 * 例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。
9 */
10 public class ReConstructBinaryTree {
11 public static void main(String[] args) {
12 Scanner sc = new Scanner(System.in);
13 while (sc.hasNext()) {
14 int n = sc.nextInt();//二叉树的节点数
15
16 int[] preorder = new int[n];//二叉树先序遍历
17 for (int i = 0; i < n; i++) {
18 preorder[i] = sc.nextInt();
19 }
20
21 int[] inorder = new int[n];//二叉树中序遍历
22 for (int i = 0; i < n; i++) {
23 inorder[i] = sc.nextInt();
24 }
25
26 TreeNode root = reConstruct(preorder, inorder);
27 System.out.print(root.val + " ");
28
29 //使用对列输出重构的二叉树
30 Queue<TreeNode> queue = new LinkedList<>();
31 queue.add(root);
32
33 //利用对列先进先出的特点
34 while (!queue.isEmpty()) {
35 TreeNode node = queue.poll();
36 if (node.left != null) {
37 System.out.print(node.left.val + " ");
38 queue.add(node.left);
39 }
40 if (node.right != null) {
41 System.out.print(node.right.val + " ");
42 queue.add(node.right);
43 }
44 }
45 }
46 }
47
48 private static TreeNode reConstruct(int[] preorder, int[] inorder) {
49 if (preorder == null || inorder == null) {
50 return null;
51 }
52
53 return reConstructCore(preorder, 0, preorder.length - 1, inorder, 0, inorder.length - 1);
54 }
55
56 private static TreeNode reConstructCore(int[] preorder, int startPre, int endPre,
57 int[] inorder, int startIn, int endIn) {
58 if (startPre > endPre || startIn > endIn) {
59 return null;
60 }
61
62 //获取根节点,先序遍历的第一个值即根节点
63 TreeNode root = new TreeNode(preorder[startPre]);
64
65 for (int i = startIn; i <= endIn; i++) {
66 if (inorder[i] == preorder[startPre]) {
67 //构建左子树
68 root.left = reConstructCore(preorder, startPre + 1, startPre + i - startIn,
69 inorder, startIn, i - 1);
70 //构建右子树
71 root.right = reConstructCore(preorder, i - startIn + startPre + 1, endPre,
72 inorder, i + 1, endIn);
73 }
74 }
75
76 return root;
77 }
78
79
80 }
81
82 class TreeNode {
83 int val;
84 TreeNode left;
85 TreeNode right;
86
87 TreeNode(int x) {
88 val = x;
89 }
90 }