五、对称二叉树
题目
给你一个二叉树的根节点 root
, 检查它是否轴对称。
题解 ------ 递归法
- 递归函数的参数设置:左右节点之间的比较,这里并不是左右子树的比较哦。
- 迭代停止条件
- 左节点为空,右节点不为空 返回false
- 左节点不为空,右节点为空 返回false
- 左节点为空,右节点也为空 返回true
- 左节点不为空,右节点也不为空,则需要判断节点相应的值
- 值不相等 返回false
- 单次递归过程(值相等的情况,则进入单层递归情况)
- 比较外侧(left->left, right->right)
- 比较内侧(left->right, right->left)
- 如果内外侧都对称,则返回true
C++
class Solution {
public:
bool isTheSame(TreeNode* left, TreeNode* right){
// 迭代参数的设置
// 左节点不为空 右节点为空
if(left != nullptr && right == nullptr) return false;
// 左节点为空 右节点不为空
else if(left == nullptr && right != nullptr) return false;
// 左节点为空 右节点为空
else if(left == nullptr && right == nullptr) return true;
// 左节点值不等于右节点值
else if(left->val != right->val) return false;
// 左节点值等于右节点值,进入单层递归
// 比较外侧
bool outside = isTheSame(left->left, right->right);
// 比较内侧
bool inside = isTheSame(left->right, right->left);
// 左右对称返回true
bool bothSide = outside && inside;
return bothSide;
}
bool isSymmetric(TreeNode* root) {
if(root == nullptr) return true;
bool result = isTheSame(root->left, root->right);
return result;
}
};
六、二叉树的最大深度
题目
给定一个二叉树 root
,返回其最大深度。
二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。
题解1 -- 递归法
C++
class Solution {
public:
int getDepth(TreeNode* node){
if(node == nullptr) return 0;
int left = getDepth(node->left);
int right = getDepth(node->right);
int depth = 1 + max(left, right);
return depth;
}
int maxDepth(TreeNode* root) {
return getDepth(root);
}
};
题解2 -- 层次遍历
C++
class Solution {
public:
int maxDepth(TreeNode* root) {
queue<TreeNode*> q;
int maxD = 0;
if(root == nullptr) return maxD;
q.push(root);
while(!q.empty()){
int size = q.size();
vector<int> vec;
while(size--){
TreeNode*tmp = q.front();
q.pop();
vec.push_back(tmp->val);
if(tmp->left) q.push(tmp->left);
if(tmp->right) q.push(tmp->right);
}
maxD++;
}
return maxD;
}
};
七、二叉树的最小深度
题目
给定一个二叉树,找出其最小深度。
最小深度是从根节点到最近叶子节点的最短路径上的节点数量。
**说明:**叶子节点是指没有子节点的节点。
题解
C++
class Solution {
public:
int getMinDepth(TreeNode* node){
if(node == nullptr) return 0;
// 根据题目的定义,最小深度是从根节点到某个叶子节点,而叶子节点则是左右节点都为空
if(node->left == nullptr && node->right != nullptr) return getMinDepth(node->right) + 1;
else if(node->left != nullptr && node->right == nullptr) return getMinDepth(node->left) + 1;
return 1 + min(getMinDepth(node->left), getMinDepth(node->right));
}
int minDepth(TreeNode* root) {
return getMinDepth(root);
}
};
八、完全二叉树的节点个数
题目
给你一棵 完全二叉树 的根节点 root
,求出该树的节点个数。
完全二叉树 的定义如下:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h
层,则该层包含 1~ 2h
个节点。
222. 完全二叉树的节点个数 - 力扣(LeetCode)
题解
C++
class Solution {
public:
int countNodes(TreeNode* root) {
queue<TreeNode*> q;
int count = 0;
if(root == nullptr) return count;
q.push(root);
while(!q.empty()){
int size = q.size();
vector<int> vec;
while(size--){
TreeNode* node = q.front();
q.pop();
vec.push_back(node->val);
if(node->left) q.push(node->left);
if(node->right) q.push(node->right);
}
count += vec.size();
}
return count;
}
};
九、平衡二叉树
题目
给定一个二叉树,判断它是否是高度平衡的二叉树。
本题中,一棵高度平衡二叉树定义为:
一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1 。
题解
C++
class Solution {
public:
int getResult(TreeNode* node){
// 停止条件
if(node == nullptr) return 0;
// left
int left = getResult(node->left);
if(left == -1) return -1;
// right
int right = getResult(node->right);
if(right == -1) return -1;
// middle
if(abs(left - right) > 1) return -1;
else return 1 + max(left, right);
}
bool isBalanced(TreeNode* root) {
return getResult(root) != -1? true: false;
}
};
十、二叉树的所有路径
题目
给你一个二叉树的根节点 root
,按 任意顺序 ,返回所有从根节点到叶子节点的路径。
叶子节点 是指没有子节点的节点。
题解
回溯机制是一种在递归算法中经常使用的技术,它确保在递归过程中对数据结构的修改能够被正确撤销,使得每次递归完成后数据结构回到原始状态。在这段代码中,回溯主要通过path.pop_back()
来实现。
path.push_back(cur->val)
: 在递归遍历二叉树的过程中,将当前节点的值加入路径(path
)中,表示当前路径经过这个节点。- 回溯的目的: 当遍历完当前节点的左子树和右子树后,需要回到上一层节点,撤销对路径的修改,以确保在递归的不同路径中不发生干扰。
path.pop_back()
: 这行代码实现了回溯。它的作用是将path
中最后一个元素弹出,即撤销对路径的最后一次修改。- 在处理左子树之后,表示回溯到上一层,撤销对左子树的修改。
- 在处理右子树之后,表示回溯到上一层,撤销对右子树的修改。
更加形象的说明
想象你置身于一座迷宫中,这座迷宫是一棵二叉树的结构。你的目标是找到通向宝藏(叶子节点)的所有路径。让我们以这个代码为例,形象描述回溯的过程:
- 起点:
- 你站在树的根节点,开始探索路径。
- 沿左子树探索:
- 你选择往左走,表示遍历当前节点的左子树。
- 沿途你记录下经过的节点值,就像在迷宫中留下标记。
- 到达叶子节点:
- 当你到达一个叶子节点,表示你找到了一条通向宝藏的路径。
- 你将这条路径记录下来,包括所有经过的节点值。
- 回溯左子树:
- 然后你需要回到上一层,撤销往左走的决策,就像在迷宫中返回到分叉路口。
- 在回溯的过程中,你擦除了最后一个标记,表示回到了上一层节点。
- 沿右子树探索:
- 接着,你决定往右走,继续探索其他可能的路径。
- 类似地,在途中你又记录下了经过的节点值。
- 到达叶子节点:
- 当你再次到达叶子节点,表示找到了另一条通向宝藏的路径。
- 你将这条路径同样记录下来。
- 回溯右子树:
- 回溯的过程再次发生,你擦除了最后一个标记,回到了上一层节点。
- 完成探索:
- 你继续这个探索和回溯的过程,直到你遍历了整棵二叉树。
- 最终,你找到了所有通向宝藏的路径。
C++
class Solution {
public:
void getResult(TreeNode* node, vector<TreeNode*> &path, vector<string> &result){
// 表示当前路径经过这个节点
path.push_back(node);
// 遇到了叶子节点,保存到result
if(node->left == nullptr && node->right == nullptr){
string tmp;
for(int i = 0; i < path.size() - 1; i++){
tmp += to_string(path[i]->val);
tmp += "->";
}
tmp += to_string(path[path.size() - 1]->val);
result.push_back(tmp);
}
// 左节点不为空
if(node->left){
getResult(node->left, path, result);
// pop出当前这个点, 不打扰下一次递归路径
path.pop_back();
}
if(node->right){
getResult(node->right, path, result);
path.pop_back();
}
}
vector<string> binaryTreePaths(TreeNode* root) {
vector<string> result;
vector<TreeNode*> path;
if(root == nullptr) return result;
getResult(root, path, result);
return result;
}
};