根据一棵树的中序遍历与后序遍历构造二叉树。
注意: 你可以假设树中没有重复的元素。
例如,给出中序遍历 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;
}
}
实现起来倒是不觉得头疼,但是给我十个脑子也不能想出这招啊