前中后序是遍历二叉树过程中处理每一个节点的三个特殊时间点
二叉树的所有问题,就是让你在前中后序位置注入巧妙的代码逻辑,去达到自己的目的。
后序位置的代码不仅可以获取参数数据,还可以获取到子树通过函数返回值传递回来的数据。一旦你发现题目和子树有关,那大概率要给函数设置合理的定义和返回值,在后序位置写代码了
两种解题思路
二叉树题目的递归解法可以分两类思路,第一类是遍历一遍二叉树得出答案,第二类是通过分解问题计算出答案,这两类思路分别对应着 回溯算法核心框架 和 动态规划核心框架。
104. 二叉树的最大深度
方法一: 遍历一遍二叉树,用一个外部变量记录每个节点所在的深度,取最大值就可以得到最大深度,这就是遍历二叉树计算答案的思路。
利用:前序位置是进入一个节点的时候,后序位置是离开一个节点的时候
出现迷之问题,执行不出错,提交出错。目前唯一办法,把辅助函数写在主函数体内,这样才能正确使用全局变量
// 主函数
var maxDepth = function(root) {
let res = 0;
let depth = 0; // 记录遍历到的节点的深度
// 二叉树遍历框架
function traverse(root) {
if(root == null) {
// 叶子节点深度大于非叶子节点
res = Math.max(res, depth);
return;
}
depth++;
traverse(root.left)
traverse(root.right)
depth--;
}
traverse(root);
return res;
};
方法二: 二叉树的最大深度可以通过子树的最大高度推导出来,这就是分解问题计算答案的思路。
利用:递归函数的定义算出左右子树的最大深度,然后推出原树的最大深度,主要逻辑自然放在后序位置。
var maxDepth = function(root) {
if (root == null) {
return 0;
}
// 利用定义,计算左右子树的最大深度
let leftMax = maxDepth(root.left);
let rightMax = maxDepth(root.right);
// 整棵树的最大深度等于左右子树的最大深度取最大值,
// 然后再加上根节点自己
let res = Math.max(leftMax, rightMax) + 1;
return res;
};
543. 二叉树的直径
给定一棵二叉树,你需要计算它的直径长度。一棵二叉树的直径长度是任意两个结点路径长度中的最大值。这条路径可能穿过也可能不穿过根结点。
每一条二叉树的「直径」长度,就是一个节点的左右子树的最大深度之和。
还是一样,全局变量写在主函数内。但让我找到了原因, 参考类似问题: LeetCode 提交后运行时代码中的全局变量并没有成功初始化,保险起见,需要在函数中重新初始化全局变量。
var diameterOfBinaryTree = function(root) {
function maxDepth(root) {
if(root == null) return 0;
let left = maxDepth(root.left)
let right = maxDepth(root.right)
let depth = Math.max(left, right) + 1
let len = left + right // 子树深度等于跟节点到叶子的边
maxlen = Math.max(maxlen, len)
return depth
}
let maxlen = 0
maxDepth(root)
return maxlen;
};
把函数,全局变量写在外面。
let maxlen = 0
function maxDepth(root) {
if(root == null) return 0;
let left = maxDepth(root.left)
let right = maxDepth(root.right)
let depth = Math.max(left, right) + 1
let len = left + right // 子树深度等于跟节点到叶子的边
maxlen = Math.max(maxlen, len)
return depth
}
var diameterOfBinaryTree = function(root) {
maxlen = 0 // 重新初始化全局变量
maxDepth(root)
return maxlen;
};
102. 二叉树的层序遍历
二叉树题型主要是用来培养递归思维的,而层序遍历属于迭代遍历,这里就过一下代码框架吧
给你二叉树的根节点 root ,返回其节点值的 层序遍历 。 (即逐层地,从左到右访问所有节点)。
var levelOrder = function(root) {
if(root == null) return [];
let queue = [], ans = []
queue.push(root)
while(queue.length) {
let temp = [], curlen = queue.length
for(let i=0; i<curlen; i++){
let node = queue.shift()
temp.push(node.val)
node.left && queue.push(node.left) // 代码功底
node.right && queue.push(node.right)
}
ans.push(temp)
}
return ans;
};