二叉树的中序遍历
二叉树的中序遍历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;
}
};