平衡二叉树
题目描述
给定一个二叉树,判断它是否是 平衡二叉树
示例 1:
输入:root = [3,9,20,null,null,15,7]
输出:true
示例 2:
输入:root = [1,2,2,3,3,null,null,4,4]
输出:false
示例 3:
输入:root = []
输出:true
解题思路
- 通过递归计算每个节点左右子树的高度,并检查它们的高度差是否大于1,以此判断树是否平衡。
- 如果发现任何子树不平衡(即高度差大于1),则立即返回-1,表示整个树不平衡。
- 如果所有节点都平衡,则返回树的实际高度,最终通过检查根节点的高度是否为-1来确定整个树是否平衡。
代码实现
测试地址:https://leetcode.cn/problems/balanced-binary-tree/
class Solution {
public:
// 计算二叉树节点的高度,如果发现不平衡则返回-1
int getHeight(TreeNode *node) {
if (node == nullptr) { // 如果节点为空,高度为0
return 0;
}
int leftHeight = getHeight(node->left); // 递归计算左子树的高度
if (leftHeight == -1) // 如果左子树不平衡,直接返回-1
return -1;
int rightHeight = getHeight(node->right); // 递归计算右子树的高度
if(rightHeight == -1) // 如果右子树不平衡,直接返回-1
return -1;
// 如果左右子树高度差大于1,则树不平衡,返回-1;否则返回当前节点的高度
return abs(leftHeight - rightHeight) > 1 ? -1 : 1 + std::max(leftHeight,rightHeight);
}
// 判断二叉树是否平衡
bool isBalanced(TreeNode *root) {
return getHeight(root) == -1 ? false : true; // 如果根节点的高度返回-1,则树不平衡,否则平衡
}
};
二叉树的所有路径
题目描述
给你一个二叉树的根节点 root
,按 任意顺序 ,返回所有从根节点到叶子节点的路径。
叶子节点 是指没有子节点的节点。
示例 1:
输入:root = [1,2,3,null,5]
输出:["1->2->5","1->3"]
示例 2:
输入:root = [1]
输出:["1"]
解题思路
递归遍历二叉树,记录从根节点到每个叶子节点的路径,并将这些路径转换为字符串格式存储在结果中。在遍历过程中,使用一个向量 path
来存储当前路径的节点值,当到达叶子节点时,将路径转换为字符串做相关处理后添加到结果向量 result
中。每次递归返回时,从 path
中移除当前节点,以便回溯到上一路径继续探索其他分支。
代码实现
测试地址:https://leetcode.cn/problems/binary-tree-paths/
class Solution {
private:
// 递归函数,用于遍历树并记录路径
void travelsal(TreeNode *cur, vector<int> &path, vector<string> &result) {
// 将当前节点的值添加到路径中
path.push_back(cur->val);
// 如果当前节点是叶子节点,则将路径转换为字符串并添加到结果中
if (cur->left == nullptr && cur->right == nullptr) {
string subPath;
for (int i = 0; i < path.size() - 1; i++) {
subPath += to_string(path[i]);
subPath += "->";
}
subPath += to_string(path[path.size() - 1]);
result.push_back(subPath);
return;
}
// 如果存在左子树,则递归遍历左子树,并在返回后从路径中移除当前节点
if (cur->left) {
travelsal(cur->left, path, result);
path.pop_back();
}
// 如果存在右子树,则递归遍历右子树,并在返回后从路径中移除当前节点
if (cur->right) {
travelsal(cur->right, path, result);
path.pop_back();
}
}
public:
// 主函数,用于初始化路径和结果,并调用遍历函数
vector<string> binaryTreePaths(TreeNode *root) {
vector<string> result; // 存储所有路径字符串的结果
vector<int> path; // 存储当前路径的节点值
if (root == nullptr)
return result; // 如果根节点为空,直接返回空结果
travelsal(root, path, result); // 从根节点开始遍历树
return result; // 返回所有路径字符串
}
};
左叶子之和
题目描述
给定二叉树的根节点 root
,返回所有左叶子之和。
示例 1:
输入: root = [3,9,20,null,null,15,7]
输出: 24
解释: 在这个二叉树中,有两个左叶子,分别是 9 和 15,所以返回 24
示例 2:
输入: root = [1]
输出: 0
解题思路
递归法:
递归遍历二叉树,查找并累加所有左叶子节点的值。在遍历过程中,如果当前节点的左子节点是叶子节点(即没有左右子节点),则将其值计入总和。通过递归调用,分别计算左子树和右子树中左叶子节点的值,并将两者相加得到最终结果。
迭代法:
使用栈来迭代遍历二叉树,查找并累加所有左叶子节点的值。在遍历过程中,如果当前节点的左子节点是叶子节点(即没有左右子节点),则将其值加到结果中。通过栈的先进后出特性,确保了树的深度优先遍历,同时正确处理了左叶子节点的值累加。
代码实现
测试地址:https://leetcode.cn/problems/sum-of-left-leaves/
递归法:
class Solution {
public:
// 计算二叉树中所有左叶子节点的值之和
int sumOfLeftLeaves(TreeNode *root) {
// 如果根节点为空,返回0
if (root == nullptr)
return 0;
// 如果根节点没有左右子节点,返回0
if (root->left == nullptr && root->right == nullptr)
return 0;
// 递归计算左子树中左叶子节点的值之和
int leftValue = sumOfLeftLeaves(root->left);
// 如果左子节点是叶子节点,则其值应被计入总和
if (root->left && !root->left->left && !root->left->right) {
leftValue = root->left->val;
}
// 递归计算右子树中左叶子节点的值之和
int rightValue = sumOfLeftLeaves(root->right);
// 计算左子树和右子树中左叶子节点值之和
int sum = leftValue + rightValue;
return sum;
}
};
迭代法:
class Solution {
public:
// 计算二叉树中所有左叶子节点的值之和
int sumOfLeftLeaves(TreeNode* root) {
// 使用栈来辅助进行迭代遍历
stack<TreeNode*> st;
// 如果根节点为空,返回0
if (root == NULL) return 0;
// 将根节点压入栈中
st.push(root);
// 初始化结果为0
int result = 0;
// 当栈不为空时,循环执行以下操作
while (!st.empty()) {
// 取出栈顶节点
TreeNode* node = st.top();
st.pop();
// 如果当前节点的左子节点是叶子节点,则将其值加到结果中
if (node->left != NULL && node->left->left == NULL && node->left->right == NULL) {
result += node->left->val;
}
// 如果当前节点有右子节点,将其压入栈中
if (node->right) st.push(node->right);
// 如果当前节点有左子节点,将其压入栈中
if (node->left) st.push(node->left);
}
// 返回计算出的左叶子节点值之和
return result;
}
};
完全二叉树的节点个数
题目描述
给你一棵 完全二叉树 的根节点 root
,求出该树的节点个数。
完全二叉树 的定义如下:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h
层,则该层包含 1 ~
2
h
2^{h}
2h 个节点。
示例 1:
输入:root = [1,2,3,4,5,6]
输出:6
示例 2:
输入:root = []
输出:0
示例 3:
输入:root = [1]
输出:1
解题思路
二叉树后序遍历思路
自底向上遍历二叉树的每个节点,计算左子树和右子树的节点数,并将它们与当前节点相加,从而得到整个树的节点总数。
层序遍历思路
通过队列实现层次遍历,每次处理一层的节点,并在处理过程中累加节点总数。
完全二叉树特性思路
如果左右子树的深度相同,则使用特定公式直接计算节点数;否则,递归计算左右子树的节点数并相加
代码实现
测试地址:https://leetcode.cn/problems/count-complete-tree-nodes/description/
普通二叉数的后序遍历:
lass Solution {
private:
// 递归函数,用于计算以给定节点为根的树的节点总数
int getNodesNum(TreeNode* cur) {
// 如果当前节点为空,返回0
if (cur == nullptr)
return 0;
// 递归计算左子树的节点数
int leftNum = getNodesNum(cur->left);
// 递归计算右子树的节点数
int rightNum = getNodesNum(cur->right);
// 计算当前树的节点数,包括当前节点
int treeNum = leftNum + rightNum + 1;
return treeNum; // 返回节点总数
}
public:
int countNodes(TreeNode* root) {
return getNodesNum(root); // 从根节点开始计算
}
};
极简写法
class Solution {
public:
// 计算二叉树的节点总数
int countNodes(TreeNode* root) {
// 如果根节点为空,返回0
if (root == NULL) return 0;
// 递归计算左子树和右子树的节点数,并加上当前节点
return 1 + countNodes(root->left) + countNodes(root->right);
}
};
层序遍历:
class Solution {
public:
int countNodes(TreeNode* root) {
queue<TreeNode*> que; // 使用队列进行广度优先搜索
if (root != nullptr)
que.push(root); // 如果根节点不为空,将其加入队列
int result = 0; // 用于记录节点总数
while (!que.empty()) { // 当队列不为空时,继续遍历
int size = que.size(); // 当前层的节点数
for (int i = 0; i < size; i++) { // 遍历当前层的所有节点
TreeNode* node = que.front(); // 取出队列头部的节点
que.pop(); // 移除队列头部的节点
result++; // 增加节点计数
if (node->left)
que.push(node->left); // 如果左子节点存在,将其加入队列
if (node->right)
que.push(node->right); // 如果右子节点存在,将其加入队列
}
}
return result; // 返回节点总数
}
};
完全二叉树定义的后序遍历:
class Solution {
public:
int countNodes(TreeNode* root) {
if (root == nullptr) // 如果根节点为空,返回0
return 0;
TreeNode* left = root->left; // 获取左子节点
TreeNode* right = root->right; // 获取右子节点
int leftDepth = 0, rightDepth = 0; // 初始化左右子树的深度
while (left) { // 计算左子树的深度
left = left->left;
leftDepth++;
}
while (right) { // 计算右子树的深度
right = right->right;
rightDepth++;
}
if (leftDepth == rightDepth) { // 如果左右子树深度相同,说明是完全二叉树
return (2 << leftDepth) - 1; // 使用公式计算完全二叉树的节点数
}
// 否则,递归计算左右子树的节点数并相加
return countNodes(root->left) + countNodes(root->right) + 1;
}
};