今天不知道晚上下不下雨,我已经4天没跑步了。这几天都是下午三四点一直下暴雨,希望今天不要下雨。明天要考六级了,打算做完这题去复习一下写译,对这次不抱希望,就是舍不得这40块的报名费,这边比湖北贵10块呜呜呜。做题先!
1、题目描述
2、逻辑分析
在数据结构中,我们只要知道一棵树的先序遍历和中序遍历就可以确定这棵树。当然中序和后序也可以遍历,而先序和后序不行。为什么不行,不过赘述,嘿嘿!题中,我们知道了先序和中序,要求这棵树。怎么求捏?
2024/6/15 是的,我昨天没做完这题,晚上吃完饭就犯困,没劲,实验室的另外两个都说要走,就早早的走了,《涅朵奇卡》看了一大半,今天晚上回去可以看完。下午裸考六级,不出意外的寄了!Anyway,先做完这题吧!
2024/6/16 哈哈啊,很难想象一道题我三天做完,拖延症犯了,昨天晚上绕湖跑了一圈,爽!今天早上将《涅朵奇卡》看完啦,虽然是王小波力荐的作品,但对我来说,并没有那么惊艳,里面的心理刻画确实很棒,但我总有一个感觉,这都是出自陀思妥耶夫斯基之口,诚然,这书是他写的,肯定出自他口了,但是角色的语气不够鲜明,经常一个人长篇的输出,有些不符合这个角色的行为,至少我这么感觉。Anyway,这也不妨碍我喜欢他的作品。
话说回来,我们继续来看这题。
算法思想:
1. 确定根节点:前序遍历的第一个元素是根节点的值。
2. 分割子树:在中序遍历中找到根节点的位置,该位置将中序遍历分为左、右两部分,分别对应左子树和右子树的节点。
3. 递归构建:对左、右子树的前序遍历和中序遍历结果,分别递归执行步骤1和步骤2,构建出左、右子树。
4. 连接子树:将左、右子树连接到根节点上,形成完整的二叉树。
3、代码演示
// 定义一个私有的Map,用于存储中序遍历中每个元素的值及其对应的索引
private Map<Integer, Integer> indexMap;
// 使用递归方法从给定的前序遍历和中序遍历中构建二叉树
public TreeNode myBuildTree(int[] preorder, int[] inorder, int preorder_left, int preorder_right,
int inorder_left, int inorder_right) {
// 如果前序遍历的索引超出了范围,说明没有节点可构建,返回null
if (preorder_left > preorder_right) {
return null;
}
// 前序遍历的第一个元素是当前子树的根节点
int preorder_root = preorder_left;
// 在indexMap中查找当前根节点在中序遍历中的索引
int inorder_root = indexMap.get(preorder[preorder_root]);
// 创建一个新的TreeNode节点,值为当前根节点的值
TreeNode root = new TreeNode(preorder[preorder_root]);
// 计算左子树的大小(即左子树在中序遍历中的元素数量)
int size_left_subtree = inorder_root - inorder_left;
// 递归构建左子树
// 注意:前序遍历中,根节点后面的size_left_subtree个元素是左子树的前序遍历结果
// 中序遍历中,从inorder_left到inorder_root-1的元素是左子树的中序遍历结果
root.left = myBuildTree(preorder, inorder, preorder_left + 1,
preorder_left + size_left_subtree, inorder_left, inorder_root - 1);
// 递归构建右子树
// 注意:前序遍历中,左子树后面的元素是右子树的前序遍历结果
// 中序遍历中,从inorder_root+1到inorder_right的元素是右子树的中序遍历结果
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,遍历中序遍历数组,将每个元素的值作为key,其索引作为value存入Map中
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);
}
以上是整体代码,说实话我还没看懂,整体思想理解了,具体代码实现还是差点意思。
4、复杂度分析
- 时间复杂度:
O(n)
,其中 n 是树中的节点个数。 - 空间复杂度:
O(n)
,除去返回的答案需要的 O(n)空间之外,我们还需要使用 O(n) 的空间存储哈希映射,以及 O(h)(其中 h
是树的高度)的空间表示递归时栈空间。这里 h < n,所以总空间复杂度为 O(n)。
over,拜拜啦,总算结束了这题。