[leetCode]106. 从中序与后序遍历序列构造二叉树
博客园:https://blog.csdn.net/renweiyi1487/article/details/109321267
题目
链接:https://leetcode-cn.com/problems/construct-binary-tree-from-inorder-and-postorder-traversal
根据一棵树的中序遍历与后序遍历构造二叉树。
注意:
你可以假设树中没有重复的元素。
例如,给出
中序遍历 inorder = [9,3,15,20,7]
后序遍历 postorder = [9,15,7,20,3]
返回如下的二叉树:
3
/ \
9 20
/ \
15 7
非索引版好理解
思路: 已知一棵树的后序遍历那么很容易找到根节点,也就是后续遍历数组中的最后一个节点。以该节点为切割点,在前序遍历数组中进行切割,将前序遍历数组切割成左右两部分,这里需要注意循环不变量原则也就是要确定切割区间的开闭状态保持不变! 前序遍历数组切割完成后根据切割后的左右子数组的长度切割后续遍历数组,这样就得到了左中序遍历数组---左后续遍历数组;右中序遍历数组----右后续遍历数组。这样就可以递归解决了,递归需要确定退出条件,当后数组长度为0时说明是空节点直接返回空,如果数组长度为1则说明是叶子节点直接返回该结点。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public TreeNode buildTree(int[] inorder, int[] postorder) {
if (inorder.length == 0 || postorder.length == 0)
return null;
return traversal(inorder, postorder);
}
private TreeNode traversal(int[] inorder, int[] postorder) {
// 第一步,如果数组大小为0说明是空节点了
if (inorder.length == 0) return null;
// 第二步,如果不为空取后续遍历数组作为节点元素
int rootValue = postorder[postorder.length - 1];
TreeNode root = new TreeNode(rootValue);
// 叶子节点
if (postorder.length == 1) return root;
// 第三步, 查找切割点
int delimiterIndex;
for (delimiterIndex = 0; delimiterIndex < inorder.length; delimiterIndex++) {
if (inorder[delimiterIndex] == rootValue) break;
}
// 第四步,切割中序遍历数组坚持左闭右开原则
int[] leftInorder = Arrays.copyOfRange(inorder, 0, delimiterIndex);
// System.out.println(delimiterIndex + 1 + " " + inorder.length);
// System.out.println(Arrays.toString(inorder));
int[] rightInorder = Arrays.copyOfRange(inorder, delimiterIndex + 1, inorder.length);
// System.out.println(Arrays.toString(rightInorder));
// 第5步,切割后续遍历数组
int[] leftPostorder = Arrays.copyOfRange(postorder, 0, leftInorder.length);
int[] rightPostorder = Arrays.copyOfRange(postorder, leftInorder.length, postorder.length - 1);
// 第六步,递归
root.left = buildTree(leftInorder, leftPostorder);
root.right = buildTree(rightInorder,rightPostorder);
return root;
}
}
索引优化版
上面代码切割数组部分使用了数组拷贝因此性能交差,下面使用索引进行优化:
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public TreeNode buildTree(int[] inorder, int[] postorder) {
if (inorder.length == 0 || postorder.length == 0)
return null;
return traversal(inorder, 0, inorder.length, postorder, 0, postorder.length);
}
private TreeNode traversal(
int[] inorder, int inorderBegin, int inorderEnd,
int[] postorder, int postorderBegin, int postorderEnd
) {
if (postorderBegin == postorderEnd) return null;
int rootValue = postorder[postorderEnd - 1];
TreeNode root = new TreeNode(rootValue);
if (postorderEnd - postorderBegin == 1) return root;
int delimiterIndex;
for (delimiterIndex = 0; delimiterIndex < inorder.length; delimiterIndex++) {
if (inorder[delimiterIndex] == rootValue)
break;
}
int leftInorderBegin = inorderBegin;
int leftInorderEnd = delimiterIndex;
int rightInorderBegin = delimiterIndex + 1;
int rightInorderEnd = inorderEnd;
int leftPostorderBegin = postorderBegin;
int leftPostorderEnd = postorderBegin + leftInorderEnd - leftInorderBegin;
int rightPostorderBegin = leftPostorderEnd;
int rightPostorderEnd = postorderEnd - 1;
root.left = traversal(
inorder, leftInorderBegin, leftInorderEnd,
postorder, leftPostorderBegin, leftPostorderEnd
);
root.right = traversal(
inorder, rightInorderBegin, rightInorderEnd,
postorder, rightPostorderBegin, rightPostorderEnd
);
return root;
}
}