105.从前序与中序遍历序列构造二叉树
给定两个整数数组 preorder
和 inorder
,其中 preorder
是二叉树的先序遍历, inorder
是同一棵树的中序遍历,请构造二叉树并返回其根节点。
示例 1:
输入: preorder = [3,9,20,15,7], inorder = [9,3,15,20,7]
输出: [3,9,20,null,null,15,7]
示例 2:
输入: preorder = [-1], inorder = [-1]
输出: [-1]
提示:
1 <= preorder.length <= 3000
inorder.length == preorder.length
-3000 <= preorder[i], inorder[i] <= 3000
preorder
和inorder
均 无重复 元素inorder
均出现在preorder
preorder
保证 为二叉树的前序遍历序列inorder
保证 为二叉树的中序遍历序列
解法:
解题之前先准备好需要的类。一个TreeNode(题目要求),一个TreeNode的工具类(用于层级打印Tree),由于树类型的题,这两个类出现较为频繁,因此,我单独抽出到公共模块中。
TreeNode:
/*** @author bwzfy* @ClassName TreeNode* @create 2024/1/24 - 14:47* @Version 1.0**/
public class TreeNode {public Integer val;public TreeNode left;public TreeNode right;public TreeNode(Integer val) {this.val = val;}public TreeNode(Integer val, TreeNode left, TreeNode right) {this.val = val;this.left = left;this.right = right;}
}
TreeNodeUtils:
import java.util.ArrayDeque;
import java.util.Queue;/*** @author bwzfy* @ClassName TreeNodeUtils* @create 2024/1/24 - 17:03* @Version 1.0**/
public class TreeNodeUtils {/*** 层级打印TreeNode* @param root*/public static void levelPrintTreeNode(TreeNode root) {Queue<TreeNode> queue = new ArrayDeque<>();queue.add(root);StringBuilder sb = new StringBuilder("[");while (!queue.isEmpty()) {TreeNode node = queue.poll();if (node.val == null) {sb.append("null, ");continue;}else {sb.append(node.val + ", ");}if (node.left != null) {queue.add(node.left);}else {queue.add(new TreeNode(null));}if (node.right != null) {queue.add(node.right);}else {queue.add(new TreeNode(null));}}sb.append("]");System.out.println(sb);}}
看到这道题的时候,脑海中第一反应就是递归,递归逻辑即为拿整个先序遍历数组和整个中序遍历数组生成TreeNode
- 首先根据先序遍历的确定根节点,根节点就是先序遍历数组的第一个元素
- 随后寻找左子树的所有数据,根据中序遍历数组,遍历整个中序数组,直到寻找到跟节点,那么根节点之前的所有元素,都是左子树的成员,这即是中序数组中构成左子树的所有数据。借此计算出左子树有多少节点假定为n,将先序数组,从根节点开始往后n个元素,这n个元素即为先序数组中构成左子树的所有数据。右子树同理
- 将上一步获取到的先序数组和中序数组中所有构成左子树的数据和右子树的数据,分别递归。
代码如下:
/*** @author bwzfy* @ClassName _105从前序与中序遍历序列构造二叉树* @create 2024/1/24 - 14:18* @Version 1.0**/
public class _105从前序与中序遍历序列构造二叉树 {public static void main(String[] args) {int[] preorder = {3, 9, 20, 15, 7};int[] inorder = {9, 3, 15, 20, 7};TreeNode treeNode = buildTree(preorder, inorder);TreeNodeUtils.levelPrintTreeNode(treeNode);}public static TreeNode buildTree(int[] preorder, int[] inorder) {if (preorder.length == 0 || inorder.length == 0) {return null;}return buildTreeSolve(preorder, 0, preorder.length, inorder, 0, inorder.length);}private static TreeNode buildTreeSolve(int[] preorder, int pStart, int pEnd, int[] inorder, int iStart, int iEnd) {if (pStart >= pEnd || iStart >= iEnd) {return null;}TreeNode root = new TreeNode(preorder[pStart]);if (pEnd - pStart == 1 || iEnd - iStart == 1) {return root;}// 中序遍历找到根节点的位置int iRootIndex = 0;for (int i = iStart; i < iEnd; i++) {if (inorder[i] == preorder[pStart]) {iRootIndex = i;break;}}int leftNum = iRootIndex - iStart;// 递归构造左树root.left = buildTreeSolve(preorder, pStart + 1, pStart + leftNum + 1, inorder, iStart, iRootIndex);// 递归构造右树root.right = buildTreeSolve(preorder, pStart + leftNum + 1, pEnd, inorder, iRootIndex + 1, iEnd);return root;}
}