写点什么

LeetCode 题解:105. 从前序与中序遍历序列构造二叉树,Simple O(n) without map,JavaScript,详细注释

用户头像
Lee Chen
关注
发布于: 2021 年 01 月 24 日
LeetCode题解:105. 从前序与中序遍历序列构造二叉树,Simple O(n) without map,JavaScript,详细注释

原题连接:https://leetcode-cn.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/


解题思路:


  1. 参考了[Simple O(n) without map](https://leetcode.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/discuss/34543/Simple-O(n))。

  2. 我们可以用如下代码,打印出递归经过的所有路径:


var buildTree = function (preorder, inorder) {  let preorderIndex = 0;  let inorderIndex = 0;  let preMap = new Map();  let preRealMap = new Map();
function build(direction, stop) { const item = {inorderIndex, stop: inorder.indexOf(stop), direction}; preMap.has(preorderIndex) ? preMap.get(preorderIndex).push(item) : preMap.set(preorderIndex, [item]);
if (inorder[inorderIndex] === stop) { return null; }
preRealMap.has(preorderIndex) ? preRealMap.get(preorderIndex).push([0,1,2]\n[1,0,2]) : preRealMap.set(preorderIndex, [item]);
const root = new TreeNode(preorder[preorderIndex++]);
root.left = build('left', root.val); inorderIndex++; root.right = build('right', stop);
return root; } const res = build('root'); console.log('preMap', preMap); console.log('preRealMap', preRealMap);
return res;};
复制代码


  1. 先考虑这样一个二叉树:


	      0	    /   \	   1     2
复制代码


前序遍历:[0,1,2]

中序遍历:[1,0,2]


打印结果如下:


preMap Map(4) {  0 => [    { inorderIndex: 0, stop: -1, direction: 'root'}  ],  1 => [    { inorderIndex: 0, stop: 1, direction: 'left' }  ],  2 => [    { inorderIndex: 0, stop: 0, direction: 'left' },    { inorderIndex: 1, stop: 1, direction: 'right' },    { inorderIndex: 2, stop: -1, direction: 'right' }  ],  3 => [    { inorderIndex: 2, stop: 2, direction: 'left' },    { inorderIndex: 3, stop: -1, direction: 'right' }  ]}
复制代码


preRealMap Map(3) {  0 => [ { inorderIndex: 0, stop: -1, direction: 'root' } ],  1 => [ { inorderIndex: 0, stop: 1, direction: 'left' } ],  2 => [ { inorderIndex: 2, stop: -1, direction: 'right' } ]}
复制代码


  1. 以及这样一个二叉树:


	      0	    /   \	   1     2	  / \   / \ 	 3   4 5   6
复制代码


前序遍历:[0,1,3,4,2,5,6]

中序遍历:[3,1,4,0,5,2,6]


打印结果如下:


preMap Map(8) {  0 => [ { inorderIndex: 0, stop: -1, direction: 'root' } ],  1 => [ { inorderIndex: 0, stop: 3, direction: 'left' } ],  2 => [ { inorderIndex: 0, stop: 1, direction: 'left' } ],  3 => [    { inorderIndex: 0, stop: 0, direction: 'left' },    { inorderIndex: 1, stop: 1, direction: 'right' },    { inorderIndex: 2, stop: 3, direction: 'right' }  ],  4 => [    { inorderIndex: 2, stop: 2, direction: 'left' },    { inorderIndex: 3, stop: 3, direction: 'right' },    { inorderIndex: 4, stop: -1, direction: 'right' }  ],  5 => [ { inorderIndex: 4, stop: 5, direction: 'left' } ],  6 => [    { inorderIndex: 4, stop: 4, direction: 'left' },    { inorderIndex: 5, stop: 5, direction: 'right' },    { inorderIndex: 6, stop: -1, direction: 'right' }  ],  7 => [    { inorderIndex: 6, stop: 6, direction: 'left' },    { inorderIndex: 7, stop: -1, direction: 'right' }  ]}
复制代码


preRealMap Map(7) {  0 => [ { inorderIndex: 0, stop: -1, direction: 'root' } ],  1 => [ { inorderIndex: 0, stop: 3, direction: 'left' } ],  2 => [ { inorderIndex: 0, stop: 1, direction: 'left' } ],  3 => [ { inorderIndex: 2, stop: 3, direction: 'right' } ],  4 => [ { inorderIndex: 4, stop: -1, direction: 'right' } ],  5 => [ { inorderIndex: 4, stop: 5, direction: 'left' } ],  6 => [ { inorderIndex: 6, stop: -1, direction: 'right' } ]}
复制代码


  1. 一前序遍历:[0,1,2]说明,这个解法有以下特点:


* 始终用前序遍历来创建根节点和左子节点。

* 将创建节点的值传入左子节点的递归,这样就标记了这个节点已被创建过。

* 将 stop 的值传入右子节点的递归,是因为右子节点的递归会运行在左子节点的递归之后,也就是它必须判断它上一次递归创建节点的值。

* 当左子节点的递归走到preorder的 0 和 1 位置时,此时它们两个节点肯定都没有被创建过,因此可以被正常创建节点,并且 1 会被链接到 0 的左子节点上。

* 当右子节点的递归走到 0、1 时,0、1 位置都已被创建过节点,会退出递归。

* 只有在右子节点的递归走到 2 时,此时preorder[2]还未被创建过节点,此时会被创建并链接到右子节点。

* 不断重复上面的过程,就可以保证左右节点都被连接到正确位置。


/** * Definition for a binary tree node. * function TreeNode(val) { *     this.val = val; *     this.left = this.right = null; * } *//** * @param {number[]} preorder * @param {number[]} inorder * @return {TreeNode} *//* */var buildTree = function (preorder, inorder) {  /**   * @description 通过不断移动前、中序遍历的索引,生成二叉树   * @param {number} stop // 停止递归的值   * @return {TreeNode}   */  let preorderIndex = 0; // 前序遍历的索引指针  let inorderIndex = 0; // 中序遍历的索引指针
function build( stop // 已生成节点的值 ) { // 如果当前中序遍历对应的值已被生成过节点,则无需重复生成 if (inorder[inorderIndex] === stop) { return null; }
// 使用谦虚遍历的值创建一个节点,同时将指针向前移动一位 const root = new TreeNode(preorder[preorderIndex++]);
// 标记当前值已被生成过节点,继续向左子节点递归 root.left = build(root.val); // 中序遍历指针向前移动,不断查找可以生成右子节点的值 inorderIndex++; // 将上层递归的结点值传入右子节点的递归,标记其已生成过节点 root.right = build(stop);
// 将当前生成好的节点返回到上一层递归,供连接到根节点 return root; }
return build();};
复制代码


发布于: 2021 年 01 月 24 日阅读数: 11
用户头像

Lee Chen

关注

还未添加个人签名 2018.08.29 加入

还未添加个人简介

评论

发布
暂无评论
LeetCode题解:105. 从前序与中序遍历序列构造二叉树,Simple O(n) without map,JavaScript,详细注释