剑指--重建二叉树

    技术2022-07-11  128

    剑指–重建二叉树

    1,题目:

    2,思路:

    递归解析:

    1.递推参数: 前序遍历中根节点的索引pre_root、中序遍历左边界in_left、中序遍历右边界in_right。2.终止条件: 当 in_left > in_right ,子树中序遍历为空,说明已经越过叶子节点,此时返回 null 。3.递推工作:4.建立根节点root: 值为前序遍历中索引为pre_root的节点值。5.搜索根节点root在中序遍历的索引i: 为了提升搜索效率,本题解使用哈希表 dic 预存储中序遍历的值与索引的映射关系,每次搜索的时间复杂度为 O(1)。6.构建根节点root的左子树和右子树: 通过调用 recur() 方法开启下一层递归。7.左子树: 根节点索引为 pre_root + 1 ,中序遍历的左右边界分别为 in_left 和 i - 1。8.右子树: 根节点索引为 i - in_left + pre_root + 1(即:根节点索引 + 左子树长度 + 1),中序遍历的左右边界分别为 i + 1 和 in_right。9.返回值: 返回 root,含义是当前递归层级建立的根节点 root 为上一递归层级的根节点的左或右子节点。

    下面是对应的图解:

    方法二:迭代法:

    1.使用前序遍历的第一个元素创建根节点。 2.创建一个栈,将根节点压入栈内。 3.初始化中序遍历下标为 0。 4.遍历前序遍历的每个元素,判断其上一个元素(即栈顶元素)是否等于中序遍历下标指向的元素。 5.若上一个元素不等于中序遍历下标指向的元素,则将当前元素作为其上一个元素的左子节点,并将当前元素压入栈内。 6.若上一个元素等于中序遍历下标指向的元素,则从栈内弹出一个元素,同时令中序遍历下标指向下一个元素,之后继续判断栈顶元素是否等于中序遍历下标指向的元素,若相等则重复该操作,直至栈为空或者元素不相等。然后令当前元素为最后一个想等元素的右节点。 7.遍历结束,返回根节点。

    3,代码:

    递归法:

    class Solution { /* 递归解析: 1.递推参数: 前序遍历中根节点的索引pre_root、中序遍历左边界in_left、中序遍历右边界in_right。 2.终止条件: 当 in_left > in_right ,子树中序遍历为空,说明已经越过叶子节点,此时返回 null 。 3.递推工作: 4.建立根节点root: 值为前序遍历中索引为pre_root的节点值。 5.搜索根节点root在中序遍历的索引i: 为了提升搜索效率,本题解使用哈希表 dic 预存储中序遍历的值与索引的映射关系,每次搜索的时间复杂度为 O(1)。 6.构建根节点root的左子树和右子树: 通过调用 recur() 方法开启下一层递归。 7.左子树: 根节点索引为 pre_root + 1 ,中序遍历的左右边界分别为 in_left 和 i - 1。 8.右子树: 根节点索引为 i - in_left + pre_root + 1(即:根节点索引 + 左子树长度 + 1),中序遍历的左右边界分别为 i + 1 和 in_right。 9.返回值: 返回 root,含义是当前递归层级建立的根节点 root 为上一递归层级的根节点的左或右子节点。 */ HashMap<Integer, Integer> dic = new HashMap<>(); int[] po; public TreeNode buildTree(int[] preorder, int[] inorder) { po = preorder; for(int i = 0; i < inorder.length; i++) dic.put(inorder[i], i); return recur(0, 0, inorder.length - 1); } TreeNode recur(int pre_root, int in_left, int in_right) { if(in_left > in_right) return null; TreeNode root = new TreeNode(po[pre_root]);//建立根节点root: 值为前序遍历中索引为pre_root的节点值。 int i = dic.get(po[pre_root]); root.left = recur(pre_root + 1, in_left, i - 1);//左子树: 根节点索引为 pre_root + 1 ,中序遍历的左右边界分别为 in_left 和 i - 1。 root.right = recur(pre_root + i - in_left + 1, i + 1, in_right);//右子树: 根节点索引为 i - in_left + pre_root + 1(即:根节点索引 + 左子树长度 + 1),中序遍历的左右边界分别为 i + 1 和 in_right。 return root; } }

    方法二:迭代法:

    class Solution { public TreeNode buildTree(int[] preorder, int[] inorder) { //迭代 /* 1.使用前序遍历的第一个元素创建根节点。 2.创建一个栈,将根节点压入栈内。 3.初始化中序遍历下标为 0。 4.遍历前序遍历的每个元素,判断其上一个元素(即栈顶元素)是否等于中序遍历下标指向的元素。 5.若上一个元素不等于中序遍历下标指向的元素,则将当前元素作为其上一个元素的左子节点,并将当前元素压入栈内。 6.若上一个元素等于中序遍历下标指向的元素,则从栈内弹出一个元素,同时令中序遍历下标指向下一个元素,之后继续判断栈顶元素是否等于中序遍历下标指向的元素,若相等则重复该操作,直至栈为空或者元素不相等。然后令当前元素为最后一个想等元素的右节点。 7.遍历结束,返回根节点。 */ if (preorder == null || preorder.length == 0) { return null; } TreeNode root = new TreeNode(preorder[0]); int length = preorder.length; Stack<TreeNode> stack = new Stack<TreeNode>(); stack.push(root); int inorderIndex = 0; for (int i = 1; i < length; i++) {//遍历前序遍历的每个元素,判断其上一个元素(即栈顶元素)是否等于中序遍历下标指向的元素。 int preorderVal = preorder[i]; TreeNode node = stack.peek(); if (node.val != inorder[inorderIndex]) { node.left = new TreeNode(preorderVal); stack.push(node.left); } else { while (!stack.isEmpty() && stack.peek().val == inorder[inorderIndex]) { node = stack.pop(); inorderIndex++; } node.right = new TreeNode(preorderVal); stack.push(node.right); } } return root; } }
    Processed: 0.012, SQL: 10