2020_9_25 每日一题 106. 从中序与后序遍历序列构造二叉树

根据一棵树的中序遍历与后序遍历构造二叉树。

注意: 你可以假设树中没有重复的元素。

例如,给出中序遍历 inorder = [9,3,15,20,7] 后序遍历 postorder = [9,15,7,20,3]
返回如下的二叉树:
_3
_/ \
9 20
__/ \
_15 7

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/construct-binary-tree-from-inorder-and-postorder-traversal
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

后序遍历的最后一个数肯定是根节点,在中序遍历中找到该数,则中序遍历中,左边的数都是左子树的,右边的数都是右子树的。然后就可以递归了,后序遍历通过长度来划分左右子树。
后序的index计算的时候容易晕,比较好的方法可能是认准了中序两索引之差和后续两索引之差相等:

class Solution {

    TreeNode rec(int[] inorder, int[] postorder, int inL, int inR, int postL, int postR) {
        
        if(inL > inR)
            return null;

        if(inL == inR)
            return new TreeNode(inorder[inL]);

        int rootVal = postorder[postR];
        TreeNode root = new TreeNode(rootVal);
        int rootIndex = inL;
        while(inorder[rootIndex] != rootVal) {
            ++rootIndex;
        }
        root.left = rec(inorder, postorder, inL, rootIndex - 1, postL, postL + (rootIndex - 1 - inL));
        root.right = rec(inorder, postorder, rootIndex + 1, inR, postR - (inR - rootIndex), postR - 1);

        return root;
    }

    public TreeNode buildTree(int[] inorder, int[] postorder) {
        //朴实无华递归
        return rec(inorder, postorder, 0, inorder.length - 1, 0, postorder.length - 1);
    }
}

中间在inorder里头找数的那一步可以优化。用一个HashMap记录inOrder的每个数的索引是多少,在要找索引的时候去HashMap里头找就好:

class Solution {

    int[] in, post;
    HashMap<Integer, Integer> inMap = new HashMap<>();

    TreeNode rec(int inL, int inR, int postL, int postR) {

        if(inL > inR)
            return null;

        if(inL == inR)
            return new TreeNode(in[inL]);

        int rootVal = post[postR];
        TreeNode root = new TreeNode(rootVal);
        int rootIndex = inMap.get(rootVal);
        
        root.left = rec(inL, rootIndex - 1, postL, postL + rootIndex - 1 - inL);
        root.right = rec(rootIndex + 1, inR, postR - inR + rootIndex, postR - 1);

        return root;
    }

    public TreeNode buildTree(int[] inorder, int[] postorder) {
        //朴实无华递归
        in = inorder;
        post = postorder;
        inMap.clear();
        for(int i = 0; i < inorder.length; ++i) {
            inMap.put(inorder[i], i);
        }
        return rec(0, inorder.length - 1, 0, postorder.length - 1);
    }
}

迭代法有些难以理解TAT
自己实现一下算了…

class Solution {

    public TreeNode buildTree(int[] inorder, int[] postorder) {
        //花里胡哨迭代
        if(inorder == null || inorder.length == 0)
            return null;
        
        int iIndex = inorder.length - 1;
        LinkedList<TreeNode> stack = new LinkedList<>();
        var root = new TreeNode(postorder[iIndex]);
        stack.push(root);

        for(int pIndex = iIndex - 1; pIndex >= 0; --pIndex) {
            TreeNode cur = new TreeNode(postorder[pIndex]);

            if(stack.peek().val != inorder[iIndex]) {
                //右孩
                stack.peek().right = cur;
            } else {
                TreeNode p = null;
                //某个祖先的左孩 一直找到有左孩的祖先 (栈顶和inorder[iIndex]相等说明现在的栈顶是前一个弹出的祖先 即前一个弹出的没有左孩)
                while(!stack.isEmpty() && stack.peek().val == inorder[iIndex]) {
                    --iIndex;
                    p = stack.pop();
                }
                p.left = cur;
            }
            stack.push(cur);
        }
        return root;
    }
}

实现起来倒是不觉得头疼,但是给我十个脑子也不能想出这招啊

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值