剑指offer:重建二叉树
重建二叉树的前置知识:
0、遍历二叉树:
(1)前序遍历:根左右 --> 先访问根节点,再前序遍历左子树,最后前序遍历右子树;
(2)中序遍历:左根右 --> 先中序遍历左子树,再访问根节点,最后中序遍历右子树。
(3)后序遍历:左右根 --> 先后序遍历左子树,再后序遍历右子树,组后访问根节点。
1、重建二叉树:
(1)前序+中序:前序遍历序列和中序遍历序列可以确定唯一的二叉树
(2)中序+后序:中序遍历序列和后序遍历序列可以确定唯一的二叉树
2、构建整个二叉树和构建子二叉树的过程相同。
重建二叉树的JS代码:
1 /* function TreeNode(x) { 2 this.val = x; 3 this.left = null; 4 this.right = null; 5 } */ 6 function reConstructBinaryTree(pre, vin) 7 { 8 // 递归结束条件 9 if (!pre || pre.length === 0) { 10 return; 11 } 12 13 // 前序遍历序列的第一个元素就是根节点 14 var treeNode = { 15 val: pre[0] 16 } 17 18 // 根据前序遍历序列的根节点,找到中序遍历的根节点及其下标 19 for(var i = 0; i < pre.length; i++) { 20 // 根据中序遍历根节点的下标,推断出该二叉树的左子树和右子树的节点数 21 if (vin[i] === pre[0]) { 22 // 根据中序遍历序列的特性和根节点的下标,可以推断出中序遍历序列的左子树和右子树 23 // 根据该二叉树的左子树和右子树节点数,推断出前序遍历序列的左子树前序遍历序列以及右子树前序遍历序列 24 treeNode.left = reConstructBinaryTree(pre.slice(1, i+1), vin.slice(0, i)); 25 treeNode.right = reConstructBinaryTree(pre.slice(i+1),vin.slice(i+1)); 26 } 27 } 28 return treeNode; 29 }
递归重建二叉树算法的重要条件:
已知条件:假设二叉树节点数量为n
0、前序遍历的特性
1、中序遍历的特性
2、二叉树的节点数量n
3、前序遍历序列的第0个元素就是根节点
推论:
0、中序遍历序列中根节点的下标i(结合条件3,可推断出)。
1、左子树节点数量为i(结合条件1、推论0,可推断出)。
2、中序遍历序列的0到i-1个元素是左子树中序遍历序列,i+1到最后一个元素是右子树中序遍历序列(结合条件1、推论1,可推断出)。
3、前序遍历序列的1到i+1个元素是左子树中序遍历序列,i+1到最后一个元素是右子树中序遍历序列(结合条件0、条件3、推论1,可推断出)。