104.二叉树的最大深度
题目链接:104. 二叉树的最大深度 - 力扣(LeetCode)
思路
-
递归法:
这里可以使用前序(中左右),也可以使用后序遍历(左右中),最后不要使用中序来,原理可以见翻转二叉树这一节
这里先用后序遍历(左右中),递归三要素如下:
- 确定递归函数的参数和返回值 —— root,深度
- 确定终止条件 —— 如果是空节点,则什么没有子节点,返回0
- 确定单层递归逻辑: 先求左子树深度,再求右子树深度,取最大值再加一
JS代码如下:
function getDepth(node){ if(node == null) return 0; let leftDepth = getDepth(node.left); let rightDepth = getDepth(node.right); let depth = Math.max(leftDepth,rightDepth) + 1; return depth; } var maxDepth = function(root) { return getDepth(root); };前序遍历也可以完成这道题
function getDepth(node, depth, result) { result.val = Math.max(result.val, depth); if (!node.left && !node.right) { return; } if (node.left) { getDepth(node.left, depth + 1, result); } if (node.right) { getDepth(node.right, depth + 1, result); } } function maxDepth(root) { if (!root) { return 0; } let result = { val: 0 }; getDepth(root, 1, result); return result.val; }JS中没有指针,所以用对象的值来保存result
这里是精简了代码,实际上单层递归逻辑是这样的:
if (node.left) { // 有子树就深度加一 depth++; // 再往下扩展 getDepth(node.left, depth, result); // 扩展到最下边就回溯上来,再去找有右子树的节点 depth--; } if (node.right) { depth++; getDepth(node.right, depth, result); depth--; } return; -
层序遍历法
稍微修改一下模板代码即可:
var maxDepth = function(root) { //二叉树的层序遍历 let queue = [],depth = 0; queue.push(root); if(root === null) { return depth; } while(queue.length !== 0) { // 记录当前层级节点数,方便之后以此弹出 let length = queue.length; depth++; for(let i = 0;i < length; i++) { let node = queue.shift(); // 存放当前弹出的节点 // 存放当前层下一层的节点 node.left && queue.push(node.left); node.right && queue.push(node.right); } //把每一层的结果放到结果数组 } return depth; };
总结
这一题既可以用深度优先的方法,又可以用广度优先的方法来做
深度优先即递归法:
后序遍历的模式:
对于每一个子节点,只需要求其左子树和右子树的深度并取最大值即可,就这样层层递归下去
前序遍历的模式:
判断逻辑需要放在最前面,所以设置一个result值用来保存每次执行后的depth结果的最大值
然后左右子树层层递归,相对来说这种算法才是一般的求深度的逻辑
后序遍历模式简单一些,这种有点类似于面向对象的思想,我只需要对每一个节点做比较左右子树深度的操作,然后让他们层层传下去即可。前序更像是面向业务逻辑,直接把全部的想清楚。
层序遍历模式:
这个还是套模板比较容易
在每遍历完一层depth就加1
比较简单
559.n叉树的最大深度
题目链接:559. N 叉树的最大深度 - 力扣(LeetCode)
思路
递归法:
var maxDepth = function(root) {
if(root == null){
return 0;
}
let depth = 0;
for(let i of root.children){
depth = Math.max(depth,maxDepth(i));
}
return depth+1;
};
注意递归的逻辑
相比于上面二叉树的递归,逻辑被简化了
迭代法:
var maxDepth = function(root) {
//二叉树的层序遍历
let queue = [],depth = 0;
queue.push(root);
if(root === null) {
return depth;
}
while(queue.length !== 0) {
// 记录当前层级节点数,方便之后以此弹出
let length = queue.length;
depth++;
for(let i = 0;i < length; i++) {
let node = queue.shift();
// 存放当前弹出的节点
// 存放当前层下一层的节点
for(let i of node.children){
queue.push(i)
}
}
//把每一层的结果放到结果数组
}
return depth;
};
总结
这里n叉数的逻辑和二叉树大致相似
对于子节点的遍历,可以用for.... of来完成
111.二叉树的最小深度
题目链接:111. 二叉树的最小深度 - 力扣(LeetCode)
第一想法
还是使用递归的后序遍历
这里并不是最大深度中把max()换成min()就好了
因为题目说了是根节点到叶子节点的最小距离
所以根节点的下一层没有节点的情况需要单独拿出来考虑
这样还是不行,因为存在这种情况
思路
实际上应该在单层递归逻辑地方做一个判断
如果左子树为空,右不为空则返回右边的深度
如果右空左不空则返回左边的深度
最后取一个最小值
function getDepth(node){
if(node == null) return 0;
let leftDepth = getDepth(node.left);
let rightDepth = getDepth(node.right)
if(node.left == null & node.right !== null){
return rightDepth + 1;
}else if(node.right == null && node.left !== null){
return leftDepth + 1;
}else{
result = Math.min(leftDepth,rightDepth) + 1;
return result;
}
}
var minDepth = function(root) {
return getDepth(root);
};
迭代法:
var minDepth = function(root) {
//二叉树的层序遍历
let queue = [],depth = 0;
queue.push(root);
if(root === null) {
return depth;
}
while(queue.length !== 0) {
// 记录当前层级节点数,方便之后以此弹出
let length = queue.length;
depth++;
for(let i = 0;i < length; i++) {
let node = queue.shift();
// 存放当前弹出的节点
// 存放当前层下一层的节点
if(!node.left && !node.right) return depth;
node.left && queue.push(node.left);
node.right && queue.push(node.right);
}
}
return depth;
};
这里的逻辑和二叉树最大深度的逻辑很相似,不同的地方在于:
if(!node.left && !node.right) return depth;
即,如果碰到没有子节点的节点,就立刻返回depth,这样可以得到最小的深度
222. 完全二叉树的节点个数
题目链接:222. 完全二叉树的节点个数 - 力扣(LeetCode)
第一想法
设置一个变量存储节点数量,层序遍历二叉树,每次有节点出队列,变量就加一
思路
递归法:
-
确定递归函数的参数和返回值
参数就是节点,返回值是节点的个数
-
确定终止条件
如果是空节点,则返回
-
确定单层递归逻辑
先求左边树节点数量,再求右边树节点数量,最后相加再+1
function count(node){
if(node == null){
return 0;
}
let left = count(node.left);
let right = count(node.right);
let sum = left + right + 1;
return sum;
}
var countNodes = function(root) {
return count(root);
};
迭代法:
var countNodes = function(root) {
let queue = [];
let num = 0;
if(root == null) return 0;
queue.push(root);
while(queue.length){
let len = queue.length;
for(let i = 0; i < queue.length; i++){
let node = queue.shift();
num++;
node.left && queue.push(node.left);
node.right && queue.push(node.right);
}
}
return num;
}
这一题还可以利用完全二叉树的性质,即要么是满二叉树,要么可以层层遍历下去,最后的子树一定是满二叉树
可以用递归来做:
var countNodes = function(root) {
//利用完全二叉树的特点
if(root === null) {
return 0;
}
let left = root.left;
let right = root.right;
let leftDepth = 0, rightDepth = 0;
while(left) {
left = left.left;
leftDepth++;
}
while(right) {
right = right.right;
rightDepth++;
}
if(leftDepth == rightDepth) {
return Math.pow(2, leftDepth+1) - 1;
}
return countNodes(root.left) + countNodes(root.right) + 1;
};