题目描述(中等难度)

106. Construct Binary Tree from Inorder and Postorder Traversal - 图1

根据二叉树的中序遍历和后序遍历还原二叉树。

思路分析

可以先看一下 105 题,直接在 105 题的基础上改了,大家也可以先根据 105 题改一改。

105 题给的是先序遍历和中序遍历,这里把先序遍历换成了后序遍历。

区别在于先序遍历的顺序是 根节点 -> 左子树 -> 右子树。

后序遍历的顺序是 左子树 -> 右子树 -> 根节点。

我们当然还是先确定根节点,然后在中序遍历中找根节点的位置,然后分出左子树和右子树。

对于之前的解法一,传数组的两个边界,影响不大,只要重新计算边界就可以了。

但是对于另外两种解法,利用 stop 和栈的算法,之前都是通过遍历前序遍历的数组实现的。所以构造过程是根节点,左子树,右子树。

但这里如果是后序遍历,我们先找根节点,所以相当于从右往左遍历,这样的顺序的话就成了,根节点 -> 右子树 -> 左子树,所以我们会先生成右子树,再生成左子树。

解法一

常规解法,利用递归,传递左子树和右子树的数组范围即可。

  1. public TreeNode buildTree(int[] inorder, int[] postorder) {
  2. HashMap<Integer, Integer> map = new HashMap<>();
  3. for (int i = 0; i < inorder.length; i++) {
  4. map.put(inorder[i], i);
  5. }
  6. return buildTreeHelper(inorder, 0, inorder.length, postorder, 0, postorder.length, map);
  7. }
  8. private TreeNode buildTreeHelper(int[] inorder, int i_start, int i_end, int[] postorder, int p_start, int p_end,
  9. HashMap<Integer, Integer> map) {
  10. if (p_start == p_end) {
  11. return null;
  12. }
  13. int root_val = postorder[p_end - 1];
  14. TreeNode root = new TreeNode(root_val);
  15. int i_root_index = map.get(root_val);
  16. int leftNum = i_root_index - i_start;
  17. root.left = buildTreeHelper(inorder, i_start, i_root_index, postorder, p_start, p_start + leftNum, map);
  18. root.right = buildTreeHelper(inorder, i_root_index + 1, i_end, postorder, p_start + leftNum, p_end - 1,
  19. map);
  20. return root;
  21. }

解法二 stop 值

这里的话,之前说了,递归的话得先构造右子树再构造左子树,此外各种指针,也应该从末尾向零走。

视线从右往左看。

  1. 3
  2. / \
  3. 9 20
  4. / \
  5. 15 7
  6. s 初始化一个树中所有的数字都不会相等的数,所以代码中用了一个 long 来表示
  7. <------------------
  8. 中序
  9. 9, 3, 15, 20, 7
  10. ^ ^
  11. s i
  12. 后序
  13. 9, 15, 7, 20, 3
  14. ^
  15. p
  16. <-------------------

pi 都从右往左进行遍历,所以 p 开始产生的每次都是右子树的根节点。之前代码里的++要相应的改成--

  1. int post;
  2. int in;
  3. public TreeNode buildTree(int[] inorder, int[] postorder) {
  4. post = postorder.length - 1;
  5. in = inorder.length - 1;
  6. return buildTreeHelper(inorder, postorder, (long) Integer.MIN_VALUE - 1);
  7. }
  8. private TreeNode buildTreeHelper(int[] inorder, int[] postorder, long stop) {
  9. if (post == -1) {
  10. return null;
  11. }
  12. if (inorder[in] == stop) {
  13. in--;
  14. return null;
  15. }
  16. int root_val = postorder[post--];
  17. TreeNode root = new TreeNode(root_val);
  18. root.right = buildTreeHelper(inorder, postorder, root_val);
  19. root.left = buildTreeHelper(inorder, postorder, stop);
  20. return root;
  21. }

解法三 栈

之前解法是构造左子树、左子树、左子树,出现相等,构造一颗右子树。这里相应的要改成构造右子树、右子树、右子树,出现相等,构造一颗左子树。和解法二一样,两个指针的话也是从末尾到头部进行。

  1. public TreeNode buildTree(int[] inorder, int[] postorder) {
  2. if (postorder.length == 0) {
  3. return null;
  4. }
  5. Stack<TreeNode> roots = new Stack<TreeNode>();
  6. int post = postorder.length - 1;
  7. int in = inorder.length - 1;
  8. TreeNode curRoot = new TreeNode(postorder[post]);
  9. TreeNode root = curRoot;
  10. roots.push(curRoot);
  11. post--;
  12. while (post >= 0) {
  13. if (curRoot.val == inorder[in]) {
  14. while (!roots.isEmpty() && roots.peek().val == inorder[in]) {
  15. curRoot = roots.peek();
  16. roots.pop();
  17. in--;
  18. }
  19. curRoot.left = new TreeNode(postorder[post]);
  20. curRoot = curRoot.left;
  21. roots.push(curRoot);
  22. post--;
  23. } else {
  24. curRoot.right = new TreeNode(postorder[post]);
  25. curRoot = curRoot.right;
  26. roots.push(curRoot);
  27. post--;
  28. }
  29. }
  30. return root;
  31. }

理解了 105 题 的话,这道题很快就出来了,完全是 105 题的逆向思考。

windliang wechat

添加好友一起进步~

如果觉得有帮助的话,可以点击 这里 给一个 star 哦 ^^

如果想系统的学习数据结构和算法,强烈推荐一个我之前学过的课程,可以点击 这里 查看详情