🧮 Algorithm Notebook
1、算法准备
1.1 牛客网编程OJ的典型输入输出
2、算法框架
2.1 动态规划
2.1.1 斐波那契数列
2.1.2 背包问题
2.1.3 贪心算法
2.1.4 序列和数组类问题
2.1.5 编辑距离
2.1.6 高楼扔鸡蛋
2.1.7 股票问题系列通解
2.1.8 最长有效括号
2.1.9 剪绳子
2.1.10 正则表达式匹配
2.2 二分查找
2.2.1 二分查找框架
2.2.2 搜索旋转排序数组
2.3 链表
2.3.1 反转链表
2.3.2 相交链表
2.3.3 合并链表
2.3.4 链表中倒数第k个节点
2.3.5 复制带随机指针的链表
2.4 排序算法
2.4.1 常见排序算法
2.5 二叉树
2.5.1 二叉树遍历
2.5.2 岛屿问题
2.5.3 二叉树路径问题
2.5.4 构造二叉树
2.6 回溯算法
2.6.1 回溯算法解题框架
2.6.2 N皇后
2.7 数组
2.7.1 删除有序数组中的重复项
2.7.2 滑动窗口最大值
2.7.3 调整数组顺序使奇数位于偶数前面
2.7.4 螺旋矩阵
2.7.5 多数元素
2.7.6 最大数
2.7.7 和为s的两个数字
2.7.8 构建乘积数组
2.7.9 两数之和
2.8 字符串
2.8.1 最小覆盖子串
2.8.2 比较版本号
2.8.3 验证IP地址
2.8.4 基本计算器 II
2.8.5 字符串解码
2.8.6 移掉 K 位数字
2.8.7 无重复字符的最长子串
2.8.8 第一个只出现一次的字符
2.8.9 翻转字符串里的单词
2.8.10 字符串转换整数 (atoi)
2.8.11 字符串四则运算
2.9 栈
2.9.1 最小栈
2.9.2 弹出序列
2.10 数学
2.10.1 用 Rand7() 实现 Rand10()
2.10.2 只出现一次的数字
2.10.3 整数反转
2.10.4 求1+2+…+n
2.10.5 二进制中1的个数
2.10.6 幂运算
2.10.7 1~n 整数中 1 出现的次数
2.10.8 数字序列中某一位的数字
2.10.9 丑数
2.10.10 n个骰子的点数
2.10.11 圆圈中最后剩下的数字
2.10.12 不用加减乘除做加法
2.10.13 x 的平方根
2.11 设计
2.11.1 LRU 缓存机制
-
+
游客
注册
登录
构造二叉树
## 根据前序遍历和中序遍历构造二叉树 ### 题目 输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。 例如,给出 ```txt 前序遍历 preorder = [3,9,20,15,7] 中序遍历 inorder = [9,3,15,20,7] ``` 返回如下的二叉树: ![](https://notebook.ricear.com/media/202104/2021-04-28_210531.png) **限制:** ```txt 0 <= 节点个数 <= 5000 ``` ### 问题分析 前序遍历性质:节点按照 `[根子树 | 左子树 | 右子树]` 排序。 中序遍历性质:节点按照 `[左子树 | 根节点 | 右子树]` 排序。 根据以上性质,可得出以下结论: 1. **前序遍历**的**首元素**为树的**根节点 `node` 的值**。 2. 在**中序遍历**中搜索**根节点 `node` 的索引**,可将**中序遍历**划分为 `[左子树 | 根节点 | 右子树]`。 3. 根据**中序遍历**中的**左/右子树的节点数量**,可将**前序遍历**划分为 `[根节点 | 左子树 | 右子树]`。 通过以上三步,可确定三个节点:**树的根节点**、**左子树根节点**、**右子树根节点**。对于树的左、右子树,仍可使用以上步骤划分子树的左右子树。 以上子树的递归性质是**分治算法**的体现,考虑通过递归对所有子树进行划分。 **分治算法解析**: 1. **递推参数:** 1. **根节点**在**前序遍历的索引** `root`。 2. **子树**在**中序遍历的左边界**`left`。 3. **子树**在**中序遍历的右边界**`right`。 2. **终止条件:** 1. 当 `left > right` 时,代表已经越过叶节点,此时返回 `null`。 3. **递推工作:** 1. **建立根节点**`node`:节点值为 `preOrder[root]`。 2. **划分左右子树:** 查找**根节点**在**中序遍历 `inOrder`** 中的索引 `i`。 3. **构建左右子树:** 开启左右子树递归。 | **根节点索引**(前序遍历) | **中序遍历左边界**(中序遍历) | **中序遍历右边界**(中序遍历) | | :---------------------------------------- | ------------------------------ | ------------------------------ | | root + 1 | left | map.get(preOrder[root]) - 1 | | root + map.get(preOrder[root]) - left + 1 | map.get(preOrder[root]) + 1 | right | 4. **返回值:** 回溯返回 `node`,作为上一层递归中根节点的左/右子节点。 > :warning: 本方法只适用于**无重复节点值**的二叉树。 ### 参考代码 ```java HashMap<Integer, Integer> inValueAndIndexMap = new HashMap<>(); // 哈希表,其中 key 为二叉树节点的值,value 为二叉树节点的值在后序遍历中的索引 /** * 剑指 Offer 07. 重建二叉树 * * @param preorder 前序遍历数组 * @param inorder 中序遍历数组 * @return 二叉树 */ public TreeNode buildTree(int[] preorder, int[] inorder) { this.preOrder = preorder; int m = inorder.length; for (int i = 0; i < m; i++) { inValueAndIndexMap.put(inorder[i], i); } return recur(preOrder, 0, 0, m - 1); } /** * 递归构建二叉树 * * @param root 根节点在前序遍历中的索引 * @param left 子树在中序遍历的左边界 * @param right 子树在中序遍历的右边界 * @return 二叉树 */ private TreeNode recur(int[] preorder, int root, int left, int right) { if (left > right) {return null;} // 已经越过叶节点,返回 null TreeNode node = new TreeNode(preOrder[root]); node.left = recur(preOrder, root + 1, left, inValueAndIndexMap.get(preOrder[root]) - 1); node.right = recur(preOrder, root + inValueAndIndexMap.get(preOrder[root]) - left + 1, inValueAndIndexMap.get(preOrder[root]) + 1, right); return node; } ``` ## 参考文献 1. [剑指 Offer 07. 重建二叉树](https://leetcode-cn.com/problems/zhong-jian-er-cha-shu-lcof)。 2. [面试题 07. 重建二叉树(递归法,清晰图解)](https://leetcode-cn.com/problems/zhong-jian-er-cha-shu-lcof/solution/mian-shi-ti-07-zhong-jian-er-cha-shu-di-gui-fa-qin)。
ricear
2022年7月21日 11:51
©
BY-NC-ND(4.0)
转发文档
收藏文档
上一篇
下一篇
手机扫码
复制链接
手机扫一扫转发分享
复制链接
Markdown文件
分享
链接
类型
密码
更新密码