这个图表明了这个二叉树的遍历顺序,但是下标是按照左闭右闭原则,我的做法是左闭右开
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
递归:
class Solution {
public TreeNode buildTree(int[] preorder, int[] inorder) {
return buildTree1(preorder, 0, preorder.length, inorder, 0, inorder.length);
}
private TreeNode buildTree1(int[] preorder, int preleft, int preright, int[] inorder, int inleft, int inright) {
if (preright - preleft < 1 || inright - inleft < 1) return null;
if (preright - preleft == 1) return new TreeNode(preorder[preright - 1]);
int rootVal = preorder[preleft];
TreeNode root = new TreeNode(rootVal);
int index = 0;
for (int i = inleft; i < inright; i ++) {
if (inorder[i] == rootVal) {
index = i;
break;
}
}
//这是原来的值,和答案相同,但是答案按照左闭右闭原则,即
//buildTree1(preorder, 0, preorder.length - 1, inorder, 0, inorder.length - 1);
//因此需要preleft + index - inleft在原下标基础上+1,其他同leecode 104题
//root.left = buildTree1(preorder, preleft + 1, preleft + 1 + index - inleft,inorder, inleft, inleft + index);
root.left = buildTree1(preorder, preleft + 1, preleft + index - inleft + 1,inorder, inleft, index);
root.right = buildTree1(preorder, preleft + 1 + index - inleft, preright,inorder, index + 1, inright);
return root;
}
}
优化方案:本题中,在中序数组中查找根节点的这个过程中套用了for循环,使复杂度增加,可以使用hashmap提前存储中序数组,需要的时候直接拿来用就可以了,这样可以降低复杂度。代码如下:
优化版本:
class Solution {
private Map<Integer, Integer> indexMap;
//优化版需要使用Map,所以方法中需要带上
public TreeNode myBuildTree(int[] preorder, int[] inorder, int preorder_left, int preorder_right, int inorder_left, int inorder_right) {
if (preorder_left > preorder_right) {
return null;
}
// 前序遍历中的第一个节点就是根节点
int preorder_root = preorder_left;
// 在中序遍历中定位根节点
int inorder_root = indexMap.get(preorder[preorder_root]);
// 先把根节点建立出来
TreeNode root = new TreeNode(preorder[preorder_root]);
// 得到左子树中的节点数目
int size_left_subtree = inorder_root - inorder_left;
// 递归地构造左子树,并连接到根节点
// 先序遍历中「从 左边界+1 开始的 size_left_subtree」个元素就对应了中序遍历中「从 左边界 开始到 根节点定位-1」的元素
root.left = myBuildTree(preorder, inorder, preorder_left + 1, preorder_left + size_left_subtree, inorder_left, inorder_root - 1);
// 递归地构造右子树,并连接到根节点
// 先序遍历中「从 左边界+1+左子树节点数目 开始到 右边界」的元素就对应了中序遍历中「从 根节点定位+1 到 右边界」的元素
root.right = myBuildTree(preorder, inorder, preorder_left + size_left_subtree + 1, preorder_right, inorder_root + 1, inorder_right);
return root;
}
public TreeNode buildTree(int[] preorder, int[] inorder) {
int n = preorder.length;
// 构造哈希映射,帮助我们快速定位根节点
indexMap = new HashMap<Integer, Integer>();
for (int i = 0; i < n; i++) {
indexMap.put(inorder[i], i);
}
return myBuildTree(preorder, inorder, 0, n - 1, 0, n - 1);
}
}