一:递归版
这道题利用后序遍历会容易些 为什么呐? 因为他需要收集左右孩子的节点并且返回给中间的节点
另外不要忘了 递归三部曲 1.确定返回值和参数 2.终止条件 3.单层判断的逻辑
var countNodes = function(root) {
// 1. 确定返回值和参数
let getNumbers = function(node){
// 2.判断终止条件
if(node === null)return 0;
//单层逻辑的判断
let leftNum = getNumbers(node.left); // 左
let rightNum = getNumbers(node.right); // 右
let sumNum = leftNum + rightNum + 1; // 中 这里+1 就是为了加上中间的节点
return sumNum;
}
return getNumbers(root)
};
二:迭代版(层序遍历)
// 迭代(层序遍历)版本 跟二叉树的层序遍历很相近
var countNodes = function(root) {
if(root === null)return 0;
// 利用队列来实现
let queue = [];
queue.push(root);
// 定义节点个数变量
let nodeNum = 0;
while(queue.length){
// 记录此时队列里面的元素长度 因为后序queue里面的长度在随时变化
let length = queue.length
while(length--){
// 这里面就是对每一层节点的操作
nodeNum++; // 记录每一层节点的个数
let node = queue.shift(); // 将队列中每一层的节点都记录并释放出来
// 进入下一层
node.left && queue.push(node.left)
node.right && queue.push(node.right)
}
}
return nodeNum;
}
三:利用完全二叉树特性求解
利用完全二叉树的特性来求解(对完全二叉树不理解的话 可以看一下前面的那个二叉树的理论基础) 也就是找满二叉树 如果整个大树不是满二叉树的话 就往子树去寻找
如果找到满二叉树的话就不用去按个遍历节点 直接利用公式 2的n次方-1 这里的n指的是二叉树的深度 所以在这之前要去确定二叉树的深度
这里利用的是递归来求解 判断是否为二叉树 就要求 左右子树的深度是一样的
let countNodes = function(root){
if(root === null)return 0;
// 终止条件
let left = root.left;
let right = root.right;
// 记录左子树的深度和右子树的深度
let leftDeep = 0,rightDeep = 0;
while(left){
left = left.left;
leftDeep++;
}
while(right){
right = right.right
rightDeep++;
}
// 如果左子树深度和右子树深度一样的话 就利用满二叉树公式2的n次方 - 1来求解(n为子树的深度)
if(leftDeep === rightDeep){
// 直接返回公式计算出来的值
return Math.pow(2, leftDeep + 1) - 1
}
// 递归 判断单层逻辑
let leftNum = countNodes(root.left)
let rightNum = countNodes(root.right)
return leftNum + rightNum + 1
}
可以直接在力扣上编译运行的代码