A 是 根节点
。C、D、F、G 是 叶子节点
。A 是 B 和 E 的 父节点
。B 和 E 是 A 的 子节点
。B、E 之间是 兄弟节点
。javascript
高度、深度、层
如上图所示。前端
为了方便理解记忆,高度就是抬头看,深度就是低头看。
java
与 高度、深度
不一样,层
类比盗梦空间里的楼,楼都是从 1 层开始计算,盗梦空间中的楼颠倒过来,从上往下。node
年初立了一个 flag,上面这个仓库在 2021 年写满 100 道前端面试高频题解,目前进度已经完成了 50%。git
若是你也准备刷或者正在刷 LeetCode,不妨加入前端食堂,一块儿并肩做战,刷个痛快。github
了解了树的基础知识后,立刻开启咱们愉快的刷题之旅,我整理了 8 道高频的 LeetCode 链表题及题解以下。面试
原题连接数组
中序遍历:先打印当前节点的左子树,再打印当前节点,最后打印当前节点的右子树 (CBDAFEG),如上图。post
const inorderTraversal = function(root) { const result = []; function pushRoot(root) { if (root !== null) { if (root.left !== null) { pushRoot(root.left); } result.push(root.val); if (root.right !== null) { pushRoot(root.right); } } } pushRoot(root); return result; };
原题连接spa
前序遍历:先打印当前节点,再打印当前节点的左子树,最后打印当前节点的右子树 (ABCDEFG),如上图。
const preorderTraversal = function(root) { const result = []; function pushRoot(node){ if (node !== null) { result.push(node.val); if (node.left !== null){ pushRoot(node.left); } if (node.right !== null) { pushRoot(node.right); } } } pushRoot(root); return result; };
后序遍历:先打印当前节点的左子树,再打印当前节点的右子树,最后打印当前节点 (CDBFGEA),如上图。
const postorderTraversal = function(root) { const result = []; function pushRoot(node) { if (node !== null) { if (node.left !== null) { pushRoot(node.left); } if (node.right !== null) { pushRoot(node.right); } result.push(node.val); } } pushRoot(root); return result; };
const isSameTree = function(p, q) { if (p === null && q === null) return true; if (p === null || q === null) return false; if (p.val !== q.val) return false; return isSameTree(p.left, q.left) && isSameTree(p.right, q.right); };
先明确,所谓“对称”,也就是两个树的根节点相同
且
const isSymmetric = function(root) { if (root === null) return true return isEqual(root.left, root.right) // 比较左右子树是否对称 }; const isEqual = function(left, right) { // 递归终止条件 if (left === null && right === null) return true // 对称 if (left === null || right === null) return false // 不对称 // 比较左右子树的 root 值以及左右子树是否对称 return left.val === right.val && isEqual(left.left, right.right) && isEqual(left.right, right.left) }
按照树的深度将每层对应的节点添加到对应层的数组中便可。
const levelOrder = function(root) { if (!root) return [] const res = [] dfs(root, 0, res) return res }; const dfs = function(root, depth, res) { if (!root) return // 递归终止条件 if (!res[depth]) res[depth] = [] res[depth].push(root.val) // 存入每层的节点值 dfs(root.left, depth + 1, res) // drill down dfs(root.right, depth + 1, res) }
根据层次返回其对应的结果集合。
const levelOrder = function(root) { if (!root) return [] const queue = [root] const res = [] while (queue.length > 0) { const arr = [] let len = queue.length while (len) { let node = queue.shift() arr.push(node.val) if (node.left) queue.push(node.left) if (node.right) queue.push(node.right) len-- } res.push(arr) } return res };
树的深度 = 左右子树的最大深度 + 1
const maxDepth = function(root) { if (!root) { // 递归终止条件 return 0 } else { const left = maxDepth(root.left) const right = maxDepth(root.right) return Math.max(left, right) + 1 } };
层序遍历时记录树的深度。
二叉树的层序遍历可参考轻松拿下二叉树的层序遍历
const maxDepth = function(root) { let depth = 0 if (root === null) { return depth } const queue = [root] while (queue.length) { let len = queue.length while (len--) { const cur = queue.shift() cur.left && queue.push(cur.left) cur.right && queue.push(cur.right) } depth++ } return depth };
Google:咱们 90% 的工程师都用你写的软件(Homebrew),但你无法在白板上翻转二叉树,因此翻滚吧,蛋炒饭。
原推截图,至今仍在。 Max Howell 当年吐槽以后 LeetCode 立刻加入了这道题。
会了这道题,是否是咱们也能够超越世界级大牛了?(狗头保命)
首先明确,所谓二叉树的翻转须要知足如下两点:
const invertTree = function(root) { if (root === null) return null // 递归终止条件 invertTree(root.left) invertTree(root.right) const temp = root.left root.left = root.right root.right = temp return root }
固然你也能够将上面的 2,3 两个步骤颠倒执行,也就是先交换两棵子树的位置,再对其内部进行翻转。
const invertTree = function(root) { if (root === null) return null // 递归终止条件 const temp = root.left root.left = root.right root.right = temp invertTree(root.left) invertTree(root.right) return root }
层序遍历遍历二叉树,当根结点出列时,翻转它的左右子树。而后将其左右子节点入列,以便下一层时翻转。
二叉树的层序遍历可参考轻松拿下二叉树的层序遍历
const invertTree = (root) => { if (root == null) return null; const queue = [root]; while (queue.length) { const cur = queue.shift(); [cur.left, cur.right] = [cur.right, cur.left]; if (cur.left) queue.push(cur.left); if (cur.right) queue.push(cur.right); } return root; }