题目链接:力扣
大概思路:
完全二叉树思路:(利用完全二叉树性质来完成题目)
先明确完全二叉树的定义:
1.除底层节点可能不是满的,底层节点以上的节点都是满的。
2.底层节点不是满的情况下,节点要都靠在最左边,不能有断裂。
然后了解完全二叉树有且只有两种情况,并利用这个特性来计算完全二叉树的节点数量
1.满二叉树(可以用2^树深度 - 1 来计算,注意这里根节点深度为1(后面看到代码的解释就知道了))
2.底层的叶子节点没有满(这个情况继续向下递归,一定会遇见满二叉树,如下图)
思路就是一直向下递归,遇见满二叉树就计算出结果返回,因为就算是非满二叉树,也可以继续递归,直到找到满二叉树为止(一定会找到),像上图那个只有一个节点的满二叉树,算完值返回后,它的上一个节点也会变成一个满二叉树了,计算完就继续返回。
-
问题来了,在代码里如何判断它是满二叉树?(编译器没有人的眼睛,不能直接看出来)
可以判断节点左右子树的深度,按照完全二叉树的定义,相同就代表是满二叉树,不相同就代表是非满二叉树。(注意下图不是,因为有断裂)
所以大概思路就是:
“二叉树后序遍历的基础上” + “加上是不是满二叉树判断,判断是“就”计算并返回上层递归” + “最后返回最终值就行” 。
代码思路:(递归三步曲)
1.确定函数参数和返回类型:
参数就是传入树的根节点,返回就返回以该节点为根节点二叉树的节点数量,所以返回值为int类型。
int countNodes(TreeNode* root){}
2.终止条件:
如果为空节点的话,就返回0,表示节点数为0。
if (cur == NULL) return 0;
判断下面的节点是不是满二叉树,是就计算并返回
大概意思:双指针指向节点的左右子树,然后两指针不断向左和右遍历,直到本身变成空节点,然后结束循环,得到左右子树深度,接下来做判断,深度相等,是满二叉树,返回计算的值。
if (root == nullptr) return 0;
// 开始根据做深度和有深度是否相同来判断该子树是不是满二叉树
TreeNode* left = root->left;
TreeNode* right = root->right;
int leftDepth = 0, rightDepth = 0; // 这里初始为0是有目的的,为了下面求指数方便
while (left) { // 求左子树深度
left = left->left;
leftDepth++;
}
while (right) { // 求右子树深度
right = right->right;
rightDepth++;
}
if (leftDepth == rightDepth) {
return (2 << leftDepth) - 1; // 注意(2<<1) 相当于2^2,返回满足满二叉树的子树节点数量
}
3.单层循环逻辑:
int leftTreeNum = countNodes(root->left); // 左
int rightTreeNum = countNodes(root->right); // 右
int result = leftTreeNum + rightTreeNum + 1; // 中
return result;
4.总代码
class Solution {
public:
int countNodes(TreeNode* root) {
if (root == nullptr) return 0;
TreeNode* left = root->left;
TreeNode* right = root->right;
int leftDepth = 0, rightDepth = 0; // 这里初始为0是有目的的,为了下面求指数方便
while (left) { // 求左子树深度
left = left->left;
leftDepth++;
}
while (right) { // 求右子树深度
right = right->right;
rightDepth++;
}
if (leftDepth == rightDepth) {
return (2 << leftDepth) - 1; // 注意(2<<1) 相当于2^2,所以leftDepth初始为0
}
int leftTreeNum = countNodes(root->left); // 左
int rightTreeNum = countNodes(root->right); // 右
int result = leftTreeNum + rightTreeNum + 1; // 中
return result;
}
};
个人想法:
h1和h2标题之间字体大小差距太小了,做笔记不好看,嗯。