力扣——从前序与中序遍历序列构造二叉树
创作时间:
作者:
@小白创作中心
力扣——从前序与中序遍历序列构造二叉树
引用
CSDN
1.
https://blog.csdn.net/weixin_49332521/article/details/145646360
题目描述
解题思路
方法一:递归实现
- 根据前序遍历可以确定根节点
- 在中序遍历中找到根节点,从而确定左右子树的区间
- 知道左右子树的区间后,分别在前序遍历中查找左右子树的根节点,然后递归构建左右子树
这种方法的核心是通过递归不断缩小问题规模,每次递归都需要确定当前子树的根节点以及左右子树的边界。
方法二:栈与指针实现
- 前序遍历顺序为“中左右”,中序遍历顺序为“左中右”
- 假设没有右子树,前序和中序的结果是相反的
- 前序遍历是从上到下,中序遍历是从下到上,两者是逆序关系
- 当中序遍历的顺序被打破时,说明出现了右子树,此时中序遍历中打破逆序的节点就是其前一个节点的右子节点
这种方法通过栈来辅助实现,具体步骤如下:
- 将前序遍历的节点依次入栈,每个入栈的节点都暂时当作根节点处理
- 当栈顶节点与中序遍历的第一个节点相同时,说明这是树最左下的节点
- 在前序遍历中,这个最左下节点后面的节点(即下一个入栈的节点)必定是一个右子节点
- 通过在中序遍历中寻找打破逆序的位置,可以确定右子节点的父节点
代码实现
方法一:递归实现
class Solution {
private Map<Integer, Integer> indexMap;
// 除了数组,其他参数都是下标
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);
}
}
方法二:栈与指针实现
class Solution {
public TreeNode buildTree(int[] preorder, int[] inorder) {
if (preorder == null || preorder.length == 0) {
return null;
}
TreeNode root = new TreeNode(preorder[0]);
Deque<TreeNode> stack = new LinkedList<TreeNode>();
stack.push(root);
int inorderIndex = 0;
for (int i = 1; i < preorder.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;
}
}
代码详解:
方法一:通过递归实现,主要利用了前序遍历和中序遍历的特点。前序遍历的第一个元素是根节点,通过在中序遍历中找到根节点的位置,可以确定左右子树的范围。然后递归地对左右子树进行相同的操作。
方法二:通过栈来辅助实现。核心思想是利用前序遍历和中序遍历的顺序关系。前序遍历是从上到下,中序遍历是从下到上,当中序遍历的顺序被打破时,说明出现了右子树。通过栈来维护当前处理的节点,并根据中序遍历的顺序来确定右子节点的位置。
热门推荐
如何分析和应对投资中的风险?这种分析和应对如何提高投资成功率?
基于选择性硬金电镀工艺的连接器金耗控制技术研究
小学数学原理1:14 - 为什么是减法?
秋季野钓鲫鱼时用什么窝料和饵料效果最好最详解!
红宝石的特征与鉴别方法
刘备集团中,赵云只怕这4人,其中2个惹不起,2个打不过
5部经典深海恐怖悬疑片,带你探索海洋深处的神秘与恐惧
智能网联汽车产品安全管理指南出台,专家热议自动驾驶安全问题
OpenWrt路由器的IPv6配置指南
侧路椎间孔镜的上关节突腹侧切除
如何在缴纳养老保险时做出最优选择?这种选择有哪些考虑因素?
理财档案丨70款个人养老金保险挑花眼!固定收益or浮动收益,怎么选更划算?
专著、编著和译著,啥区别?一文给你讲清楚
电脑锁定:多种方式介绍如何锁定电脑,保护个人隐私
打造完美肌膚的祕密:卸妝油推薦指南
如何分析股票市场的交易情况?这种交易情况如何影响投资者决策?
品牌社会化的“参与感革命”:如何让用户成为品牌的一部分?
药物辅料硬脂酸镁的比表面积测定方法
松下洗衣机故障代码,具体原因和解决办法
乙肝患者饮食指南:这些食物有助于肝脏健康
牡丹原产地在哪里?揭秘牡丹的起源与分布特点?
针砭时弊:揭示社会问题的锐利之笔
如何打开Windows注册表命令?注册表命令有哪些?
手机配置参数对比?如何快速比较不同品牌手机性能?
射频消融 VS 冷冻消融,关于房颤消融,您了解多少?
颈椎酸痛怎么治疗
重要通知!今晚,油价→
免费模式是否必然牺牲用户体验?
智驾价格“打下去”:车企密集“亮剑”,下探到6万元车型
体检报告中的"钙化":到底是怎么回事?