概念
二叉树
二叉树是一种 每个节点最多有两个子树 的树状结构
-
深度优先遍历有三种顺序:
前序:中→左→右
中序:左→中→右
后序:左→右→中(删除二叉树时会使用的遍历)
-
广度优先遍历
层序遍历(也可以使用深度遍历的思想)
遍历
树形结构
/**
* Definition for a binary tree node.
* function TreeNode(val, left, right) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
*/
/**
* @param {TreeNode} root
* @return {number[]}
*/
前序:中→左→右
// 递归版本
var preorderTraversal = function(root) {
let result = []
var preOrderTraverseNode = (node) => {
if(node) {
// 先根节点
result.push(node.val);
// 然后遍历左子树
preOrderTraverseNode(node.left);
// 再遍历右子树
preOrderTraverseNode(node.right);
}
}
preOrderTraverseNode(root);
return result;
};
// 利用栈辅助 遍历
const preOrderTraverseUnRecur = (root) => {
let res = [];
let stack = [root];
let node = null;
while(stack.length !== 0) {
node = stack.pop();
// 第一步的时候,先访问的是根节点
res.push(node.val);
if(node.right) {
stack.push(node.right)
}
// 因为pop是取出最后一个元素,所以我们要确保首先拿到的是左节点
if(node.left) {
stack.push(node.left)
}
}
return res;
}
中序:左→中→右
// 递归
var inorderTraversal = function(root) {
let result = []
var preOrderTraverseNode = (node) => {
if(node) {
// 先遍历左子树
preOrderTraverseNode(node.left);
// 然后根节点
result.push(node.val);
// 再遍历右子树
preOrderTraverseNode(node.right);
}
}
preOrderTraverseNode(root);
return result;
};
// 非递归
function inorderTraversal (root) {
let res = [];
let stack = [];
while(stack.length > 0 || root){
if(root){
stack.push(root);
root = root.left;
} else {
root = stack.pop();
if(root.val) res.push(root.val);
root = root.right;
}
}
return res;
}
后序:左→右→中
// 递归
var inorderTraversal = function(root) {
let result = []
var preOrderTraverseNode = (node) => {
if(node) {
preOrderTraverseNode(node.left);
preOrderTraverseNode(node.right);
result.push(node.val);
}
}
preOrderTraverseNode(root);
return result;
};
// 非递归版本
var postorderTraversal = function(root) {
let res = [];
let stack = [];
if(root) stack.push(root);
while(stack.length){
root = stack.pop();
if(root.val) res.**unshift**(root.val);
if(root.left) stack.push(root.left);
if(root.right) stack.push(root.right);
}
return res;
};
// 解题思路: 后序遍历与前序遍历不同的是:
// 后序遍历是左右根
// 而前序遍历是根左右
// 如果我们把前序遍历的 list.push(node.val) 变更为 list.unshift(node.val) (遍历结果逆序),那么遍历顺序就由 根左右 变更为 右左根
// 然后我们仅需将 右左根 变更为 左右根 即可完成后序遍
层序遍历
// 层序遍历
// // DFS(深度优先遍历)
var levelOrder = function(root) {
let res = [];
let levelTree = function(node, level){
if(!res[level]) res[level] = [];
if(node.val !== undefined) res[level].push(node.val);
if(node.left) levelTree(node.left, level+1);
if(node.right) levelTree(node.right, level+1);
}
if(root) levelTree(root, 0);
return res;
};
// BFS(广度优先遍历)
var levelOrder = function(root) {
let res = [];
let queue = [];
if(root) queue.unshift(root);
while(queue.length){
let cur = [];
let nextQue = [];
while(queue.length){
let node = queue.shift();
if(node.val !== undefined) cur.push(node.val);
if(node.left) nextQue.push(node.left);
if(node.right) nextQue.push(node.right);
}
res.push(cur);
queue = nextQue;
}
return res;
};
常用考察
二叉树最大深度
给定一个二叉树,找出其最大深度。
二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。
说明: 叶子节点是指没有子节点的节点。
// 深度遍历,比较每条路径
var maxDepth = function(root) {
if(!root) return 0;
let maxDep = 0;
const deep = function(root, n){
if(root.val) n++;
maxDep = Math.max(maxDep, n);
if(root.left) deep(root.left, n);
if(root.right) deep(root.right, n);
}
deep(root, 0);
return maxDep;
};
// 广度遍历,记录每层的树节点
var maxDepth = function(root) {
if(!root) return 0;
let maxDep = 0;
let queue = [root];
while(queue.length){
maxDep++;
let curQue = [];
while(queue.length){
let node = queue.shift();
if(node.left) curQue.push(node.left);
if(node.right) curQue.push(node.right);
}
queue = curQue;
}
return maxDep;
};
对称二叉树
给定一个二叉树,检查它是否是镜像对称的。
// 递归
var isSymmetric = function(root) {
if (root === null) return true;
const isMirror = function(left, right){
if(left === null && right === null) return true;
if(left === null || right === null) return false;
return (left.val === right.val) && isMirror(left.left, right.right) && isMirror(left.right, right.left);
}
return isMirror(root.left, root.right);
};
// 迭代
var isSymmetric = function(root) {
if (root == null) return true
let queue = [root]
while(queue.length){
let curArr = [];
let nextQue = [];
while(queue.length){
let node = queue.shift();
if(node === null){
curArr.push('null');
} else {
curArr.push(node.val);
nextQue.push(node.left);
nextQue.push(node.right);
}
}
if(Array.from(curArr).reverse().toString() !== curArr.toString()) return false;
queue = nextQue;
}
return true;
};
路径总和
给你二叉树的根节点 root 和一个表示目标和的整数 targetSum ,判断该树中是否存在 根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和 targetSum 。
叶子节点 是指没有子节点的节点。
var hasPathSum = function(root, targetSum) {
if(root === null) return false;
if(root.val === targetSum && root.left == null && root.right == null) return true;
targetSum = targetSum - root.val;
return hasPathSum(root.left, targetSum) || hasPathSum(root.right, targetSum);
};