目录
二叉树的深度和高度
- 二叉树节点的深度:指从根节点到该节点的最长简单路径边的条数或者节点数(取决于深度从0开始还是从1开始)
- 二叉树节点的高度:指从该节点到叶子节点的最长简单路径边的条数后者节点数(取决于高度从0开始还是从1开始)
前序遍历求深度,后序遍历求高度。层序遍历求二叉树的最大深度/最大高度
前序遍历求深度
// 前序遍历求二叉树的最大深度
class Solution{
public:
int result; // 记录遍历过程中的最大深度
// getdepth(TreeNode* node, int depth)
// 参数1:当前节点
// 参数2:当前节点的深度
void getdepth(TreeNode *node, int depth){
// 更新全局变量result以记录已访问过的最大深度
result = depth > result ? depth : result;
// 递归结束条件:当到达叶子节点时
if (node->left == NULL && node->right == NULL)return;
// 遍历左子树
if (node->left){
getdepth(node->left, depth + 1);
}
// 遍历右子树
if (node->right){
getdepth(node->right, depth + 1);
}
}
int maxDepth(TreeNode *root)
{
result = 0; // 初始化结果变量
if (root == NULL)return result;
getdepth(root, 1); // 从根节点开始,深度设为1
return result;
}
};
后序遍历求高度
//后序遍历求二叉树的最大高度
class Solution {
public:
int getHeight(TreeNode* node) {
if (node == NULL) return 0;
int leftdepth = getdepth(node->left); // 左
int rightdepth = getdepth(node->right); // 右
int depth = 1 + max(leftdepth, rightdepth); // 中
return depth;
}
int maxHeight(TreeNode* root) {
return getHeight(root);
}
};
精简代码:
class Solution {
public:
int maxDepth(TreeNode* root) {
if (root == null) return 0;
return 1 + max(maxDepth(root->left), maxDepth(root->right));
}
};
层次遍历求二叉树的最大深度/最大高度
int maxDepth(TreeNode *root)
{
// 如果二叉树为空,其深度为0
if (root == NULL)
return 0;
int depth = 0; // 初始化深度为0
queue<TreeNode *> que; // 创建一个队列用于广度优先搜索
que.push(root); // 将根节点加入队列
// 当队列不为空时继续循环
while (!que.empty())
{
int size = que.size(); // 获取当前层的节点数量
depth++; // 深度增加1
// 遍历当前层的所有节点
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);
}
}
// 返回最终的深度值
return depth;
}
104.二叉树的最大深度
题目链接:104. 二叉树的最大深度 - 力扣(LeetCode)
给定一个二叉树 root
,返回其最大深度。
解题思路:
根节点的高度就是二叉树的最大深度,所以本题中我们可以通过后序求的根节点高度来求的二叉树最大深度,也可以采用前序遍历求二叉树的最大深度。当然也可以使用层序遍历来求
后序
class Solution {
public:
int getdepth(TreeNode* node) {
if (node == NULL) return 0;
int leftdepth = getdepth(node->left); // 左
int rightdepth = getdepth(node->right); // 右
int depth = 1 + max(leftdepth, rightdepth); // 中
return depth;
}
int maxDepth(TreeNode* root) {
return getdepth(root);
}
};
前序
class Solution {
public:
int result;
void getdepth(TreeNode* node, int depth) {
result = depth > result ? depth : result; // 中
if (node->left == NULL && node->right == NULL) return ;
if (node->left) { // 左
getdepth(node->left, depth + 1);
}
if (node->right) { // 右
getdepth(node->right, depth + 1);
}
return ;
}
int maxDepth(TreeNode* root) {
result = 0;
if (root == 0) return result;
getdepth(root, 1);
return result;
}
};
层序
class Solution {
public:
int maxDepth(TreeNode* root) {
if (root == NULL) return 0;
int depth = 0;
queue<TreeNode*> que;
que.push(root);
while(!que.empty()) {
int size = que.size();
depth++; // 记录深度
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);
}
}
return depth;
}
};
相关题目:559. N 叉树的最大深度 - 力扣(LeetCode)
111.二叉树的最小深度
题目链接:111. 二叉树的最小深度 - 力扣(LeetCode)
给定一个二叉树,找出其最小深度。
解题思路:
其实求的是根节点到叶子节点的最小距离,就是求高度的过程,不过这个最小距离 也同样是最小深度。
注意处理图示情况
后序
int minDepth(TreeNode* root) {
if (root == nullptr) {
return 0;
}
if (root->left == nullptr && root->right == nullptr) {
// 当前节点是叶子节点
return 1;
}
// 如果左子树或右子树为空,则递归计算另一侧的最小深度
int leftDepth = root->left ? minDepth(root->left) : INT_MAX; // 左
int rightDepth = root->right ? minDepth(root->right) : INT_MAX; //右
// 返回两侧子树的最小深度加1
return std::min(leftDepth, rightDepth) + 1; //中
}
前序
int result;//定义全局变量result用于记录最小深度
void getMinDepth(TreeNode* cur, int depth) {
if (cur == nullptr) {
return;
}
if (cur->left == nullptr && cur->right == nullptr) {
// 当前节点是叶子节点
result = depth < result ? depth : result;
return;
}
// 递归遍历左右子树
if (cur->left) {
getMinDepth(cur->left, depth + 1);
}
if (cur->right) {
getMinDepth(cur->right, depth + 1);
}
}
int minDepth(TreeNode* root) {
result = INT_MAX; // 初始化最小深度为最大整数值
if (root == nullptr) {
return 0;
}
getMinDepth(root, 1); // 从根节点开始,深度为1
return result;
}
110.平衡二叉树
题目链接:110. 平衡二叉树 - 力扣(LeetCode)
给定一个二叉树,判断它是否是 平衡二叉树。一棵高度平衡二叉树定义为:一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过1。
解题思路:后序遍历计算左右子树高度,比较左右子树高度差
class Solution {
public:
int getHeight(TreeNode* cur) {
if (cur == nullptr) {
// 空节点的高度为0
return 0;
}
// 递归计算左子树的高度
int leftHeight = getHeight(cur->left);
if (leftHeight == -1) {
// 如果左子树不平衡,则整个子树不平衡
return -1;
}
// 递归计算右子树的高度
int rightHeight = getHeight(cur->right);
if (rightHeight == -1) {
// 如果右子树不平衡,则整个子树不平衡
return -1;
}
// 检查左右子树的高度差是否超过1
if (abs(leftHeight - rightHeight) > 1) {
// 高度差超过1,子树不平衡
return -1;
}
// 返回当前节点的最大高度加1
return std::max(leftHeight, rightHeight) + 1;
}
bool isBalanced(TreeNode* root) {
int height = getHeight(root);
// 如果getHeight返回-1,则表示二叉树不平衡
return height != -1;
}
};
222.完全二叉树的节点个数
题目链接:222. 完全二叉树的节点个数 - 力扣(LeetCode)
给你一棵 完全二叉树 的根节点 root
,求出该树的节点个数。
解题思路:
方法1:遍历二叉树,计数节点个数。可以使用深度遍历,也可以使用广度遍历
方法2:利用完全二叉树的性质
完全二叉树只有两种情况,情况一:就是满二叉树,情况二:最后一层叶子节点没有满。
对于情况一,可以直接用 2^树深度 - 1 来计算,注意这里根节点深度为1。
对于情况二,分别递归左孩子,和右孩子,递归到某一深度一定会有左孩子或者右孩子为满二叉树,然后依然可以按照情况1来计算。
关键在于如何去判断一个左子树或者右子树是不是满二叉树呢?
在完全二叉树中,如果递归向左遍历的深度等于递归向右遍历的深度,那说明就是满二叉树。如图:
在完全二叉树中,如果递归向左遍历的深度不等于递归向右遍历的深度,则说明不是满二叉树,如图:
int countNodes(TreeNode* root) {
if (root == nullptr) {
return 0;
}
int leftDepth = 0;
int rightDepth = 0;
TreeNode* cur = root;
// 计算左子树的深度
while (cur->left) {
leftDepth++;
cur = cur->left;
}
cur = root;
// 计算右子树的深度
while (cur->right) {
rightDepth++;
cur = cur->right;
}
// 如果左子树和右子树的深度相同,则是一棵完全二叉树
if (leftDepth == rightDepth) {
return (2 << leftDepth) - 1;
}
// 如果不是完全二叉树,则递归计算左右子树的节点数
return countNodes(root->left) + countNodes(root->right) + 1;
}
513.找树左下角的值
题目链接:513. 找树左下角的值 - 力扣(LeetCode)
给定一个二叉树,在树的最后一行找到最左边的值。
解题思路:
注意,本题找到的是最左边的值,不是左叶子。本题采用层次遍历就很容易解决,就不加赘述了。这里讲一下递归法。
问题1:如何确保最后一行?
树的最后一行 ,也就是要找深度最大的叶子节点。可以采用前序遍历求二叉树的深度,找到最大深度,然后返回。
问题2:那么如何确保找到的是最左边的叶子节点?
前序遍历是中左右,所以我们是先处理左节点再处理右节点。也就是说在同一层深度中,我们是先访问的左节点,再访问右节点。我们只要保证先左再右,就可以了。
class Solution {
public:
int maxDepth; // 记录最大深度
int firstLeft; // 记录最底层最左边节点的值
void find(TreeNode* cur, int depth) {
if (!cur) // 如果当前节点为空,则直接返回
return;
if (depth > maxDepth) { // 如果当前节点的深度大于已记录的最大深度
maxDepth = depth; // 更新最大深度
firstLeft = cur->val; // 记录当前节点的值作为最底层最左边节点的值
}
// 递归地处理左子树和右子树
find(cur->left, depth + 1);
find(cur->right, depth + 1);
}
int findBottomLeftValue(TreeNode* root) {
maxDepth = INT_MIN; // 初始化最大深度为最小整数值
find(root, 1); // 调用find函数从根节点开始查找
return firstLeft; // 返回最底层最左边节点的值
}
};