如果在每一次递归好像都有“要查一下”的条件,例如当前点是不是nullptr,当前点作为root是不是perfect tree,这些条件就放到“特殊情况”那里去写。都写完了以后再开始递归过程。
力扣
注意:
1. 区分高度和深度。高度是从leaf往上遍历,深度是从root下来。
2. 1) 求高度用后序遍历,因为【左右中】的逻辑,遍历完左右后,把高度传给parent,然后+1,是求高度的逻辑。
2) 求深度用前序遍历。
3. 二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。
root的高度就是二叉树的最大深度。所以此时按【高度】的求法(后序遍历)也是可行的,从leaf往上求
4. 若为空节点,则高度为0
5. 所以本题实际上是【post-order】,先找出左/右子树谁是maxDepth,然后再+1(中间的一个节点)。是【左右中】的逻辑。
力扣
1.思路类似上一题的后序遍历,从下往上遍历,每遍历完一层得到这一层的maxDepth后+1。
2. 终止条件:if(root == nullptr) return 0
3. 具体递归部分为:
for(int i = 0; i < root->children.size(); i++){
depth = max(depth, maxDepth(root->children[i]);
}
注意一直用depth记录不要每次更新为0了。
4. 最后return 1+depth。
力扣
1. 终止条件依然是:if(root == nullptr) return 0; 递归都不要忘了终止条件!
2. 重点是特殊情况:当左子树为nullptr但右子树不是时,此时的最小深度应该是 1+minDepth(右子树),而不是1+min(左,右) = 1。反之同理。具体就是如图所示这个情况:
具体代码为:
if(root->left == nullptr && root->right != nullptr){
return 1 + minDepth(root->right);
} else if (root->left != nullptr && root->right == nullptr){
return 1 + minDepth(root->left);
}
3. 讨论完特殊情况后,就按maxDepth类似处理即可。
1 + min(minDepth(root->left), minDepth(root->right));
力扣
perfect tree: 全满的
complete tree: 最后一行集中在左边,其余都是满的
1. 终止条件:也就是“特殊情况”的分类讨论,如果是perfect tree的话可以用公式计算出节点数。
1) 计算perfect tree节点(第一层算1):pow(2, Depth) - 1
2) 如何判断是不是perfect:左子树外侧的深度 == 右子树外侧的深度
注意:为什么只需要判断外侧,因为complete tree最后一行是集中在左侧的,所以一旦出现不perfect,外侧的深度一定会不一样。
因此对于左右子树,都从leftNode = root和rightNode = root开始。然后leftNode只需要一路向左,rightNode一路向右:
//特殊情况
int leftDepth = 0;
int rightDepth = 0;
TreeNode* leftNode = root;
TreeNode* rightNode = root;
while(leftNode){
leftNode = leftNode->left;
leftDepth++;
}
while(rightNode){
rightNode = rightNode->right;
rightDepth++;
}
if(leftDepth == rightDepth){ //perfect tree
return pow(2, leftDepth)-1; //此时leftDepth和rightDepth一样所以随便选一个就行
}
//再进行递归部分
return 1 + countNodes(root->left) + countNodes(root->right);