这是我参与2022首次更文挑战的第23天,活动详情查看:2022首次更文挑战
给定两个整数数组 preorder 和 inorder ,其中 preorder 是二叉树的先序遍历, inorder 是同一棵树的中序遍历,请构造二叉树并返回其根节点。
输入: preorder = [3,9,20,15,7], inorder = [9,3,15,20,7] 输出: [3,9,20,null,null,15,7]
我只能说,误入歧途,原本想找一个简单题做一下,看着这前序和中序,还想都很熟悉的样子
其实吧,这道题,考的就是一个思维,当你通窍了,瞬间就觉得不难了,我就在看完题解之后,我还想了好长一段时间,这到底是怎么回事。
要想知道我们这道怎么做,我们首先要知道,我们的三种遍历顺序
- 前序:根 →左 →右
- 中序:左 →根 →右
- 后序:左 →右 →根
我们这道题就主要用到了前两个,那我们就需要找到,我们这两种遍历,都有什么顺序,我们打眼一看,就看到,我们两种遍历的一个共同点,就是最后访问我们的右节点,访问左节点和根节点的顺序正好是反的
通过前序遍历我们可以确定我们根节点,再根据我们的中序遍历,我们可以找到他的左右子节点
我们要注意的一点是,我们根据前序,我们就只能确定我们的根节点,根绝中序遍历的时候,我们只能确定根节点前面的一个数,是他的左节点,根节点后面的不一定是他的右节点
当我们把这个道理弄清楚之后,我们就可以开始我们代码的编写
public TreeNode buildTree(int[] preorder, int[] inorder) {
//首先我们需要创建哈希表来存入我们的中序遍历及位置,
//因为我们需要根据我们的节点值,来确定我们根节点在中序遍历中的位置
//通过根节点来分割我们的左右子树
Map<Integer,Integer> map = new HashMap<Integer, Integer>();
for (int i = 0; i < inorder.length; i++) {
//因为通过节点值寻找,所以我们的key为节点值
map.put(inorder[i],i);
}
return buildTree(preorder,map,0, preorder.length-1,0,inorder.length-1 );
}
//我们的中序遍历直接通过map的方式传入我们的方法
//pLeft,pRight,iLeft,iLeft,为我们两种遍历的左右边界
//因为我们两种遍历只是根节点和左节点的位置不同
public TreeNode buildTree(int[] preorder,Map<Integer,Integer> map,int pLeft,int pRight,int iLeft, int iLeft,t){
if(pLeft>pRight){
return null;
}
//这个是我们根节点在我们前序遍历的位置
int pRoot = pLeft;
//这个是我们根节点在我们中序遍历的位置
int iRoot = map.get(preorder[pLeft]);
//创建我们的根节点
TreeNode root = new TreeNode(preorder[pRoot]);
//通过我们的中序的遍历根节点的位置确定我们的左子树的节点数量
int leftSize = iRoot - iLeft;
//通过递归的方式,慢慢确定节点位置,这是一种自顶而下的方式
//pLeft+1:因为第一个是我们的根节点,向右移位(确定新的先序遍历左边界)
//pLeft+leftSize:左边界加上左子树节点数量(确定新的先序遍历右边界)
//在中序遍历中与前序遍历先对应的边界
//iLeft:左边界
//根节点的左侧
root.left = buildTree(preorder,map,pLeft+1,*pLeft+l*eftSize,iLeft,iRoot-1);
//我们刚刚分割了前半部分,这回就是我们的后半部分
root.right = buildTree(preorder, map, pLeft+leftSize+1,pRight, iRoot+1, iRight);
return root;
其实,整个的代码的过程就是我们不断地先确定他的根节点→左子树,当左侧完成之后,就是小树的右子树,向上结束