Day16二叉树深度
By HQWQF 2023/12/28
笔记
104.二叉树的最大深度
给定一个二叉树,找出其最大深度。
二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。
说明: 叶子节点是指没有子节点的节点。
示例: 给定二叉树 [3,9,20,null,null,15,7],
返回它的最大深度 3 。
递归法
核心思路是二叉树的任意子树的深度等于其左右子树的深度中大的那个+1。
这里区分一下二叉树的深度和高度:
- 二叉树节点的深度:指从根节点到该节点的最长简单路径边的条数或者节点数(取决于深度从0开始还是从1开始)
- 二叉树节点的高度:指从该节点到叶子节点的最长简单路径边的条数或者节点数(取决于高度从0开始还是从1开始)
根节点的高度就是二叉树的最大深度
递归法代码
class Solution {
public:
int maxDepth(TreeNode* root) {
return getdepth(root,0);
}
int getdepth(TreeNode* node,int deep)
{
if(node == nullptr){return deep;}
return max(getdepth(node->left,deep+1),getdepth(node->right,deep+1));
}
};
另外有更加简洁的写法,节点将自己左右孩子的高度返回给其父节点:
class solution {
public:
int maxDepth(TreeNode* root) {
if (root == null) return 0;
return 1 + max(maxDepth(root->left), maxDepth(root->right));
}
};
迭代法
迭代法可以使用层序遍历的迭代法作为基础,将写入结果列表改为自增变量:
class Solution {
public:
int maxDepth(TreeNode* root) {
queue<TreeNode*> que;
if (root != NULL) que.push(root);
int result = 0;
while (!que.empty()) {
int size = que.size();
vector<int> vec;
// 这里一定要使用固定大小size,不要使用que.size(),因为que.size是不断变化的
for (int i = 0; i < size; i++) {
TreeNode* node = que.front();
que.pop();
if (node->left) que.push(node->left);
if (node->right) que.push(node->right);
}
result++;
}
return result;
}
};
111.二叉树的最小深度
给定一个二叉树,找出其最小深度。
最小深度是从根节点到最近叶子节点的最短路径上的节点数量。
说明: 叶子节点是指没有子节点的节点。
示例:
给定二叉树 [3,9,20,null,null,15,7],
返回它的最小深度 2
递归法
这个题咋一看好像和上一题差不多,但是如果直接把max换成min的话,递归到碰到空节点就开始了回溯,实际上得到的是第一次碰到空节点的深度,为了检测叶子节点,我们要检测递归到的左右孩子是否都为空才回溯。
class Solution {
public:
int minDepth(TreeNode* root) {
if(!root){return 0;}
return getdepth(root,1);
}
int getdepth(TreeNode* node,int deep)
{
if(node->left == nullptr && node->right == nullptr){return deep;}
int l = 2147483647;
if(node->left != nullptr)
{
l = getdepth(node->left,deep+1);
}
int r = 2147483647;
if(node->right != nullptr)
{
r = getdepth(node->right,deep+1);
}
return min(l,r);
}
};
同样有更加精简的代码:
class Solution {
public:
int minDepth(TreeNode* root) {
if (root == NULL) return 0;
if (root->left == NULL && root->right != NULL) {
return 1 + minDepth(root->right);
}
if (root->left != NULL && root->right == NULL) {
return 1 + minDepth(root->left);
}
return 1 + min(minDepth(root->left), minDepth(root->right));
}
};
迭代法
迭代法的话可以使用层序遍历,遍历到叶子节点时以当前层数尝试更新结果变量。
class Solution {
public:
int minDepth(TreeNode* root) {
queue<TreeNode*> que;
if (root != NULL) que.push(root);
else{return 0;}
int tier = 0;
int res = 100000;
while (!que.empty()) {
int size = que.size();
vector<int> vec;
// 这里一定要使用固定大小size,不要使用que.size(),因为que.size是不断变化的
for (int i = 0; i < size; i++) {
TreeNode* node = que.front();
que.pop();
if (node->left) que.push(node->left);
if (node->right) que.push(node->right);
if(!node->left && !node->right){res = min(res,tier + 1);}
}
tier++;
}
return res;
}
};
222.完全二叉树的节点个数
给你一棵 完全二叉树 的根节点 root
,求出该树的节点个数。
完全二叉树 的定义如下:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h
层,则该层包含 1~ 2h
个节点。
以普通二叉树来做
核心思路是二叉树的任意子树的节点数等于起左右子树的节点之和+1。
代码
class Solution {
public:
int countNodes(TreeNode* root) {
if(root == nullptr){return 0;}
return countNodes(root->left) + countNodes(root->right) + 1;
}
};
以完全二叉树来做
由完全二叉树的定义可知,完全二叉树可以看作由若干是满二叉树子树的结合。
而对于满二叉树,我们可以轻松利用其高度n来计算其节点数(2^n)-1,所以我们可以在常规计算节点数的基础上,检测以当前节点为根的子树是否为满二叉树,是的话就通过其高度直接返回节点数。
至于检测子树是否为满二叉树,对于完全二叉树中的满二叉树子树而言,只要从子树的根节点一路向左和一路向右探测深度,如果深度一样的话就是满二叉树子树,当然这是对于完全二叉树中的满二叉树子树而言的
代码
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
}
return countNodes(root->left) + countNodes(root->right) + 1;
}
};