Foo说Bar道——算法篇之二叉树重建新解

输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。

代码很简单,直接上代码:

import java.util.HashMap;
public class Solution {

    public TreeNode reConstructBinaryTree(int[] pre, int[] in) {
        if (pre.length == 0) return null;
        if (pre.length == 1) return new TreeNode(pre[0]);

        //初始化
        int len = pre.length;
        TreeNode[] nodeArr = new TreeNode[len];
        Map<Integer,Integer> indices = new HashMap();
        for (int i = 0; i < len; i++) {
            indices.put(in[i], i);
            nodeArr[i] = new TreeNode(in[i]);
        }

        /** * 先序遍历序列pre中满足: * 1.对于任意相邻位置i, j = i + 1对应节点,在中序遍历中的顺序存在两种情况: * a)中序中,j在i前,这时一定满足j是i的左孩子 * b)中序中,i在j前,这时分两种情况 * 1)中序序列i~j位置的中间不存在i和j的公共父节点,j是i的直接右孩子 * 2)中序序列i~j位置的中间存在i和j的公共父节点,则最靠近j一侧的父节点就是最近的公共父节点,并且j一定是这个公共父节点的右孩子 * 判断是否是父节点直接看该节点的左,右孩子是否为空即可 * */
        int first, second;
        //遍历pre的所有相邻i,j
        for (int i = 0; i < len - 1; i++) {
            //first,second是两个节点在中序中的位置
            first = indices.get(pre[i]);
            second = indices.get(pre[i + 1]);

            //对应上述b条件
            if (first < second) {
                int t = second;
                TreeNode tn;
                //从second位置反向查找第一个父节点
                //找不到父节点的话t刚好就等于first
                //这里条件做了个优化,
                //查找i,j中间的父节点,父节点左右孩子都为空,正常左右孩子不会相等,如果相等,则一定都为空
                while ( t > first && (tn = nodeArr[t]).left == tn.right ) t--;
                //这里t可能指向的是最近公共父节点,也可能是i(就是first)节点
                nodeArr[t].right = nodeArr[second];
            }
            //对应a条件
            else nodeArr[first].left = nodeArr[second];
        }
        return nodeArr[indices.get(pre[0])];
    }
}
点赞