二叉树的中序遍历
二叉树的中序遍历LeetCode94
题目:给定一个二叉树的根节点 root ,返回 它的 中序 遍历
输入:root = [1,null,2,3] 输出:[1,3,2]
输入:root = [] 输出:[]
二叉树的前、中、后序遍历是对根节点而言,即根节点的遍历顺序,都可以使用递归或者迭代的方式
使用循环的方式时,先将左字数都push到数组中,当左子树遍历完成后取出最近的节点,然后遍历该节点的右子树
// 使用while循环var inorderTraversal = function (root) {const result = []if (root === null) return result;const queue = [];let p = root;while (p || queue.length > 0) {if (p !== null) {queue.push(p);p = p.left;continue;}p = queue.pop();result.push(p.val);p = p.right;}return result;};// 使用递归var inorderTraversal = function (root) {const result = []if (root === null) return result;function traverse(root) {if (root.left !== null) {traverse(root.left)}result.push(root.val);if (root.right !== null) {traverse(root.right);}}traverse(root);return result;};
二叉树的层序遍历
二叉树的层序遍历LeetCode102
题目:给你二叉树的根节点 root ,返回其节点值的 层序遍历 。 (即逐层地,从左到右访问所有节点)
输入:root = [3,9,20,null,null,15,7] 输出:[[3],[9,20],[15,7]]
输入:root = [] 输出:[]
输入:root = [1] 输出:[[1]]
层序遍历即一层一层的遍历二叉树,遍历当前层的数组,拿到value,并将当前层的左右子树都存入另一个数组,如此循环
var levelOrder = function(root) {const result = [];if (root === null) return result;let currentLevel = [root];while(currentLevel.length > 0) {const nextLevel = []const currentLevelResult = currentLevel.map(item => {if (item.left) {nextLevel.push(item.left)}if (item.right) {nextLevel.push(item.right)}return item.val;});result.push(currentLevelResult);currentLevel = nextLevel;}return result;};
从前序与中序遍历构造二叉树
从前序与中序遍历构造二叉树LeetCode105
题目:给定两个整数数组 preorder 和 inorder ,其中 preorder 是二叉树的先序遍历, inorder 是同一棵树的中序遍历,请构造二叉树并返回其根节点。
输入: preorder = [3,9,20,15,7], inorder = [9,3,15,20,7] 输出: [3,9,20,null,null,15,7]
输入: preorder = [-1], inorder = [-1] 输出: [-1]
前序遍历的数组的特征:[根节点,左子树前序遍历,右子树前序遍历],中序遍历的数组的特征:[左子树中序遍历,根节点,右子树中序遍历],只要找到根节点,就能划分左右子树
先构造根节点,并根据根节点将中序遍历数组划分为左右子树,递归遍历,中序遍历数组的左子树遍历完成时,前序遍历数组的左子树根节点已经全部移出,继续遍历右子树
var buildTree = function (preorder, inorder) {const traverse = function (subInorder) {if (subInorder.length === 0) {return null}const rootValue = preorder.shift();const root = new TreeNode(rootValue);const temp = subInorder.findIndex(value => value === rootValue);if (temp === -1) {return null;}root.left = traverse(subInorder.slice(0, temp));root.right = traverse(subInorder.slice(temp + 1, subInorder.length));return root;}const root = traverse(inorder);return root;};
从中序与后序遍历构造二叉树
从中序与后序遍历构造二叉树LeetCode106
题目:给定两个整数数组 inorder 和 postorder ,其中 inorder 是二叉树的中序遍历, postorder 是同一棵树的后序遍历,请你构造并返回这颗 二叉树 。
输入:inorder = [9,3,15,20,7], postorder = [9,15,7,20,3] 输出:[3,9,20,null,null,15,7]
输入:inorder = [-1], postorder = [-1] 输出:[-1]
与上一题类似,不过后序遍历数组结枸是[左子树后序遍历数组,右子树后序遍历数组,根节点],所以构造二叉树的时候是先构造根节点,再构造右子树,然后再构造左子树
var buildTree = function(inorder, postorder) {const traverse = function (subInorder) {if (subInorder.length === 0) return null;const rootValue = postorder.pop();const root = new TreeNode(rootValue);const temp = subInorder.findIndex(value => rootValue === value);if (temp === -1) return null;root.right = traverse(subInorder.slice(temp + 1, subInorder.length));root.left = traverse(subInorder.slice(0, temp));return root;}const root = traverse(inorder);return root;};
二叉树的最近公共祖先
二叉树的最近公共祖先LeetCode236
题目:给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
输入:root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1 输出:3
输入:root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4 输出:5
输入:root = [1,2], p = 1, q = 2 输出:1
中心思想是先判断根节点的左右子树与p,q是否存在父子关系,如果左子树与右子树均存在父子关系,则最近的公共祖先就肯定是根节点了,如果只有左子树存在父子关系,返回左子树,如果只有右子树存在父子关系,返回右节点
为了确保返回的左右节点和根节点是距离p,q最近的,需要先递归到左右子树的最下面的节点,然后一层一层网上判断,类似于后续遍历
var lowestCommonAncestor = function (root, p, q) {if (root === null) {return null;}if (p === root || q === root) {return root;}const leftNode = lowestCommonAncestor(root.left, p, q);const rightNode = lowestCommonAncestor(root.right, p, q);// 如果leftNode与rightNode均有值,则返回他们的根节点if (leftNode !== null && rightNode !== null) {return root;}// 如果leftNode没有值,则p或q在右节点上,返回右节点if (leftNode === null) {return rightNode;}// 如果rightNode没有值,则p或者q在左节点上,返回左节点if (rightNode === null) {return leftNode;}};
