题目:

106. 从中序与后序遍历序列构造二叉树

题解:


题解一:



在递归方法中,传入子数组的边界索引。

注意:在递归方法中,有一个数组的边界索引,得通过计算得到,计算的依据是递归方法传入的“中序遍历数组”(的子数组)和“后序遍历数组”(的子数组)的长度是一样的。我的办法是解方程计算未知数。具体需要计算哪个参数我在下面的代码中已经注明了。

下面展示了一个计算边界的方法。

例如:




2. 题解二:

可以把中序遍历的值和索引放在一个哈希表中,就不需要通过遍历得到当前根结点在中序遍历中的位置了。

3. 题解三:

后序的遍历顺序是,左右中
中序的遍历顺序是,左中右

1.根据后序建立索引,从后往前一个一个拿出来,首先拿出最后一个数a,然后找到中序里a的位置
2.中序里面a左边的就是左子树,a右边的就是右子树,递归调用就行了



4. 题解四:

目标:如何从中序与后序遍历序列构造二叉树
分析:这一类题需要我们把中序链表放入 map 中,根据后序的顺序来递归出每个节点的左子树和右子树
错误:这题需要先遍历右子树再遍历左子树,不要乱顺序
关键:以中序为基础,以后序链表从后往前的顺序构建出每个节点的左子树和右子树

代码:

1. 代码一:

/** * code106 */
public class code106 {

    public static TreeNode buildTree(int[] inorder, int[] postorder) {
        int inLen = inorder.length;
        int postLen = postorder.length;
        return build(inorder, 0, inLen - 1, postorder, 0, postLen - 1);
    }

    /** * 使用中序遍历序列 inorder 的子区间 [inLeft, inRight] 与后序遍历序列 postorder 的子区间 [postLeft, * postRight] 构建二叉树 * * @param inorder 中序遍历序列 * @param inLeft 中序遍历序列的左边界 * @param inRight 中序遍历序列的右边界 * @param postorder 后序遍历序列 * @param postLeft 后序遍历序列的左边界 * @param postRight 后序遍历序列的右边界 * @return 二叉树的根结点 */

    public static TreeNode build(int inorder[], int inLeft, int inRight, int postorder[], int postLeft, int postRight) {
        if (inLeft > inRight || postLeft > postRight) {
            return null;
        }
        int pivot = postorder[postRight];
        int pivotIndex = inLeft;
        while (inorder[pivotIndex] != pivot) {
            pivotIndex++;
        }
        TreeNode root = new TreeNode(pivot);
        root.left = build(inorder, inLeft, pivotIndex - 1, postorder, postLeft, postRight - inRight + pivotIndex - 1);
        root.right = build(inorder, pivotIndex + 1, inRight, postorder, postRight - inRight + pivotIndex,
                postRight - 1);
        return root;
    }

    public static void main(String[] args) {
        int inorder[] = { 9, 3, 15, 20, 7 };
        int postorder[] = { 9, 15, 7, 20, 3 };
        TreeNode tree = buildTree(inorder, postorder);
        System.out.println("***************************************");
        TreeOperation.show(tree);
        System.out.println("***************************************");
    }
}

2. 代码二:


/** * code106 */

import java.util.*;

public class code106 {

    public static TreeNode buildTree(int[] inorder, int[] postorder) {
        int inLen = inorder.length;
        int postLen = postorder.length;
        Map<Integer, Integer> map = new HashMap<>();
        for (int i = 0; i < inLen; i++) {
            map.put(inorder[i], i);
        }
        return build(0, inLen - 1, postorder, 0, postLen - 1, map);
    }

    /** * 使用中序遍历序列 inorder 的子区间 [inLeft, inRight] 与后序遍历序列 postorder 的子区间 [postLeft, * postRight] 构建二叉树 * * @param inLeft 中序遍历序列的左边界 * @param inRight 中序遍历序列的右边界 * @param postLeft 后序遍历序列的左边界 * @param postRight 后序遍历序列的右边界 * @return 二叉树的根结点 */

    public static TreeNode build(int inLeft, int inRight, int postorder[], int postLeft, int postRight,
            Map<Integer, Integer> map) {
        if (inLeft > inRight || postLeft > postRight) {
            return null;
        }
        int pivot = postorder[postRight];
        int pivotIndex = map.get(pivot);
        TreeNode root = new TreeNode(pivot);
        root.left = build(inLeft, pivotIndex - 1, postorder, postLeft, postRight - inRight + pivotIndex - 1, map);
        root.right = build(pivotIndex + 1, inRight, postorder, postRight - inRight + pivotIndex, postRight - 1, map);
        return root;
    }

    public static void main(String[] args) {
        int inorder[] = { 9, 3, 15, 20, 7 };
        int postorder[] = { 9, 15, 7, 20, 3 };
        TreeNode tree = buildTree(inorder, postorder);
        System.out.println("***************************************");
        TreeOperation.show(tree);
        System.out.println("***************************************");
    }
}

3. 代码三:


/** * code106 */

import java.util.*;

public class code106 {

    // 解法三:
    public static int index;

    public static TreeNode buildTree(int[] inorder, int[] postorder) {
        index = postorder.length - 1;
        return build(inorder, postorder, 0, inorder.length - 1);
    }

    public static TreeNode build(int inorder[], int postorder[], int inStart, int inEnd) {
        if (inStart > inEnd) {
            return null;
        }
        int val = postorder[index--];
        for (int i = inStart; i <= inEnd; i++) {
            if (inorder[i] == val) {
                TreeNode root = new TreeNode(val);
                root.right = build(inorder, postorder, i + 1, inEnd);
                root.left = build(inorder, postorder, inStart, i - 1);
                return root;
            }
        }
        return null;
    }

    public static void main(String[] args) {
        int inorder[] = { 9, 3, 15, 20, 7 };
        int postorder[] = { 9, 15, 7, 20, 3 };
        TreeNode tree = buildTree(inorder, postorder);
        System.out.println("***************************************");
        TreeOperation.show(tree);
        System.out.println("***************************************");
    }
}

4. 代码四:


/** * code106 */

import java.util.*;

public class code106 {

    // 解法四:
    public static int pindex;// 后序的索引

    public static TreeNode buildTree(int[] inorder, int[] postorder) {
        pindex = postorder.length - 1;// 因为二叉树的第一个节点对应后序的最后一个,从最后一个开始
        Map<Integer, Integer> map = new HashMap<>();// 存放中序的映射
        for (int i = 0; i < inorder.length; i++) {
            map.put(inorder[i], i);
        }
        return build(postorder, 0, inorder.length - 1, map);
    }

    /** * * @param postorder 后序链表 * @param inLeft 中序的左边界 * @param inRight 中序的右边界 * @return 二叉树节点 */

    public static TreeNode build(int postorder[], int inLeft, int inRight, Map<Integer, Integer> map) {
        if (inLeft > inRight) {
            return null;
        }
        int val = postorder[pindex--];// 从最后一个开始初始化为TreeNode
        TreeNode root = new TreeNode(val);
        int index = map.get(val);// 得到在中序的索引
        root.right = build(postorder, index + 1, inRight, map);// 先遍历右子树
        root.left = build(postorder, inLeft, index - 1, map);// 再遍历左子树
        return root;
    }

    public static void main(String[] args) {
        int inorder[] = { 9, 3, 15, 20, 7 };
        int postorder[] = { 9, 15, 7, 20, 3 };
        TreeNode tree = buildTree(inorder, postorder);
        System.out.println("***************************************");
        TreeOperation.show(tree);
        System.out.println("***************************************");
    }
}

参考:

  1. 分治法(Python、Java)
  2. 从中序与后序遍历序列构造二叉树
  3. 图解构造二叉树之中序+后序
  4. 思路清晰,代码简洁,和105题思路一致(Python)
  5. 详细通俗的思路分析,多解法
  6. 简单易懂版
  7. 简单的Java解法 ,击败了 87.84%,详细注释
  8. 哈希