【LeetCode】105. Construct Binary Tree from Preorder and Inorder Traversal 解题报告


转载请注明出处:http://blog.csdn.net/crazy1235/article/details/51559645


Subject

出处:https://leetcode.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/


Given preorder and inorder traversal of a tree, construct the binary tree.

Note:
You may assume that duplicates do not exist in the tree.


Explain

给定一个二叉树的先序遍历中序遍历,构造出一颗二叉树。

二叉树的遍历分为先序遍历、中序遍历、后序遍历、层序遍历。

而通过先序遍历和中序遍历、中序遍历和后序遍历 是可以还原该二叉树结构的。


Solution

solution 1

递归方式

     4
   /   \
  2     7
 / \   / \
1   3 6   9

以上面的二叉树为例。
其先序遍历结果是:【4 2 1 3 7 6 9】
中序遍历结果是:【1 2 3 4 6 7 9】

对先序遍历来说:

先序遍历的每个值表示的结点都是接下来的若干结点的父结点。

比如【4】是这个二叉树的根结点。
【2】是【1 3】的父结点。
【1】是 空的父结点,也即使叶子结点。

对中序遍历来说:

根结点一定在中间位置,中间左边是左子树,右边是右子树。
比如【4】左边是【1 2 3】是根结点的左子树,右边是【6 7 9】是根结点的右子树。
对于【2】来说,【1】是其左子树,【3】是其右子树。
……
依次类推。

很明显,这是一个递归过程。

public TreeNode buildTree(int[] preorder, int[] inorder) {
        if (preorder == null || preorder.length == 0) {
            return null;
        }
        if (inorder == null || inorder.length == 0) {
            return null;
        }

        if (preorder.length != inorder.length) {
            return null;
        }

        return build(preorder, inorder, 0, 0, inorder.length - 1);
    }
public TreeNode build(int[] preorder, int[] inorder, int preIndex,
            int startInIndex, int endInIndex) {
        if (endInIndex < startInIndex) {
            return null;
        }
        TreeNode node = new TreeNode(preorder[preIndex]);

        // the index of current node in inorder
        int index = getIndexInInorder(inorder, preorder[preIndex]);
        int lenL = index - startInIndex;
        int lenR = endInIndex - startInIndex - lenL;

        if (lenL > 0) {
            node.left = build(preorder, inorder, preIndex + 1, startInIndex,
                    index - 1);
        }
        if (lenR > 0) {
            node.right = build(preorder, inorder, preIndex + lenL + 1,
                    index + 1, endInIndex);
        }

        return node;
    }
//获得val值在inorder中的下标
public int getIndexInInorder(int[] inorder, int val) {
        for (int i = 0; i < inorder.length; i++) {
            if (val == inorder[i]) {
                return i;
            }
        }
        return -1;
    }

build( ) 是主要递归方法。

因为参数是两个int数组。需要指定preorder数组的下标,还需要指定当前递归中中序对应的若干结点,用 startInIndexendInIndex 分别表示开始和结束下标。


LeetCode平台测试通过之后,发现build方法可以稍微优化一些。如下:

public TreeNode build2(int[] preorder, int[] inorder, int preIndex,
            int startInIndex, int endInIndex) {
        if (endInIndex < startInIndex) {
            return null;
        }
        int currentVal = preorder[preIndex];
        TreeNode node = new TreeNode(currentVal);

        // the index of current node in inorder
        int index;
        for (index = startInIndex; index <= endInIndex; index++) {
            if (currentVal == inorder[index]) {
                break;
            }
        }
        // int lenL = index - startInIndex;
        // int lenR = endInIndex - index;

        if (index > startInIndex) {
            node.left = build(preorder, inorder, preIndex + 1, startInIndex,
                    index - 1);
        }
        if (endInIndex > index) {
            node.right = build(preorder, inorder, preIndex + index
                    - startInIndex + 1, index + 1, endInIndex);
        }

        return node;
    }

优化之前,RunTime 是 :8ms
beats 73.81% of java submissions.

但是问题来了:“优化之后”,在LeetCode平台测试,发现效率竟然还慢了不知为何???


solution 2

方法二是在【Discuss】频道看到的答案。
使用的是非递归方式。

    /**
     * 
     * @param preorder
     * @param inorder
     * @return
     */
    public TreeNode buildTree2(int[] preorder, int[] inorder) {
        HashMap map = new HashMap<>();
        for (int i = 0; i < inorder.length; i++) {
            map.put(inorder[i], i);
        }
        TreeNode root = null;
        TreeNode p = root;
        Stack stack = new Stack<>();
        for (int i = 0; i < preorder.length; i++) {
            int temp = map.get(preorder[i]);
            TreeNode node = new TreeNode(preorder[i]);
            if (stack.isEmpty()) {
                root = node;
//              stack.add(node);
                p = root;
            } else {
                if (temp < map.get(stack.peek().val)) {
                    p.left = node;
                    p = p.left;
                } else {
                    while (!stack.isEmpty() && temp > map.get(stack.peek().val)) {
                        p = stack.pop();
                    }
                    p.right = node;
                    p = p.right;
                }
            }
            stack.add(node);
        }

        return root;
    }

该方法的RunTime是 9ms
beats 73.29% of java submissions.

比我的方法稍微慢一点点,哈哈~


bingo~~

你可能感兴趣的:(Java开发,算法学习,LeetCode解题报告,Java,篇)