用于个人复习
- 1.二叉树的右视图
- 2.二叉树最大宽度
- 3.二叉树的最大深度
- 4.N叉树的最大深度
- 5.二叉树的最小深度
- 6.子树的最大平均值
- 7.求根节点到叶节点的数字之和
- 8.另一棵树的子树
- 9.对称二叉树
1.二叉树的右视图
给定一个二叉树的根节点root,想象自己站在它的右侧,按照从顶部到底部的顺序,从右侧所能看到的节点值。
BFS层序遍历,每一层最后一个节点就是二叉树的右侧视图,可以把BFS反过来,从右往左遍历每一行,进一步提升效率。在每一层的位置记录一下第一个
class Solution {
public:
vector<int> rightSideView(TreeNode* root) {
vector<int> res;
if(root == nullptr) return res;
queue<TreeNode*> q;
q.push(root);
while(!q.empty()){
TreeNode* last = q.front();
int size = q.size();
for(int i = 0; i < size; i ++){
TreeNode* cur = q.front();
q.pop();
if(cur->right != nullptr) q.push(cur->right);
if(cur->left != nullptr) q.push(cur->left);
}
res.push_back(last->val);
}
return res;
}
};
2.二叉树最大宽度
给你一棵二叉树的根节点 root ,返回树的 最大宽度 。
树的 最大宽度 是所有层中最大的 宽度 。
每一层的 宽度 被定义为**该层最左和最右的非空节点(即,两个端点)之间的长度。**将这个二叉树视作与满二叉树结构相同,两端点间会出现一些延伸到这一层的 null 节点,这些 null 节点也计入长度。
题目数据保证答案将会在 32 位 带符号整数范围内。
本题的关键在于要给二叉树节点按行进行编号,然后就可以通过每一行的最左侧和最右侧节点的编号推算出这一行的宽度,进而算出最大宽度。
假设父节点的编号是 x,左子节点就是 2 * x,右子节点就是 2 * x + 1。这个特性常见于完全二叉树的题目当中。
使用一个结构体来记录下节点和对应的编号
class Solution {
struct Pair{
TreeNode* node;
unsigned long long id;//int不够,编号都转换成unsigned long long
Pair(TreeNode* node, unsigned long long id) : node(node), id(id) {}
};
public:
int widthOfBinaryTree(TreeNode* root) {
if(root == nullptr) return 0;
unsigned long long maxWidth = 0;
queue<Pair> q;
q.push(Pair(root, 1));
while(!q.empty()){
int size = q.size();
unsigned long long start = 0, end = 0;
for(int i = 0; i < size; i ++){
Pair cur = q.front();
q.pop();
TreeNode* curNode = cur.node;
unsigned long long curId = cur.id;
if(i == 0) start = curId;
if(i == size - 1) end = curId;
if(curNode->left != nullptr) q.push(Pair(curNode->left, curId * 2));
if(curNode->right != nullptr) q.push(Pair(curNode->right, curId * 2 + 1));
}
maxWidth = max(maxWidth, end - start + 1); //因为end - start + 1是unsigned long long类型,所以maxWidth也必须是这个类型才可以,或者将end - start + 1单独强制转换成int,static_cast<int>(end - start + 1)
}
return maxWidth;
}
};
3.二叉树的最大深度
class Solution {
public:
int res = 0;
int maxDepth(TreeNode* root) {
if(root == nullptr) return 0;
int leftDepth = maxDepth(root->left);
int rightDepth = maxDepth(root->right);
res = max(leftDepth, rightDepth) + 1;
return res;
}
};
4.N叉树的最大深度
给定一个N叉树,找到其最大深度。
class Solution {
public:
int maxDepth(Node* root) {
if(root == nullptr) return 0;
int subTreeMaxDepth = 0;
for(Node* child : root->children) subTreeMaxDepth = max(subTreeMaxDepth, maxDepth(child));
return 1 + subTreeMaxDepth;
}
};
5.二叉树的最小深度
最小深度不能像最大深度一样用return 1 + min(leftDepth, rightDepth),因为假设是一个节点连着一个叶子节点,另一边是空,那么min(leftDepth, rightDepth)将返回0,这导致当前节点的计算深度实际上只为1,这是错误的,因为实际上有两个节点。
所以这个地方应该分别计算
class Solution {
public:
int res = 0;
int minDepth(TreeNode* root) {
if(root == nullptr) return 0;
int leftDepth = minDepth(root->left);
int rightDepth = minDepth(root->right);
if(root->left == nullptr || root->right == nullptr) res = max(leftDepth, rightDepth) + 1;
if(root->left != nullptr && root->right != nullptr) res = min(leftDepth, rightDepth) + 1;
return res;
}
};
6.子树的最大平均值
会员题。
给你一棵二叉树的根节点root,找出这棵树的每一棵子树的平均值中的最大值。
- 以value == 5的节点作为子树的根节点,得到的平均值为4
- 以value == 6的节点作为子树的根节点,得到的平均值为6
- 以value == 1的节点作为子树的根节点,得到的平均值为1
定义一个函数helper(node),返回一个arr[]数组,其中arr[0]表示以node为根节点的子树的所有元素和,arr[1]表示以node为根节点的子树的所有元素的个数。
于是,平均数就是两个相除。
class Solution {
public:
double maxMean = 0.0;
double maximumAverageSubtree(TreeNode* root) {
if (root == nullptr) return 0.0;
helper(root);
return maxMean;
}
private:
pair<int, int> helper(TreeNode* root) {
if (root == nullptr) return make_pair(0, 0);
pair<int, int> left = helper(root->left);
pair<int, int> right = helper(root->right);
// Sum of values in the subtree
int sum = left.first + right.first + root->val;
// Total number of nodes in the subtree
int count = left.second + right.second + 1;
// Update the maximum average found so far
maxMean = max(maxMean, (double)sum / count);
return make_pair(sum, count);
}
};
7.求根节点到叶节点的数字之和
给你一个二叉树的根节点 root ,树中每个节点都存放有一个 0 到 9 之间的数字。
每条从根节点到叶节点的路径都代表一个数字:
例如,从根节点到叶节点的路径 1 -> 2 -> 3 表示数字 123 。计算从根节点到叶节点生成的 所有数字之和 。
做法就是为了获取所有路径数字之和,递归遍历一遍二叉树,沿路记录下来路径上的数字,到叶子节点的时候求和。因为要求当前节点到叶子结点的序列,所以是前序遍历
class Solution {
public:
int res = 0;
int sumNumbers(TreeNode* root) {
traverse(root, 0);
return res;
}
void traverse(TreeNode* root, int sum)
{
sum = sum * 10 + root->val;
if(root->left == nullptr && root->right == nullptr)
{
res += sum;
return;
}
if(root->left)
traverse(root->left, sum);
if(root->right)
traverse(root->right, sum);
}
};
8.另一棵树的子树
给你两棵二叉树 root 和 subRoot 。检验 root 中是否包含和 subRoot 具有相同结构和节点值的子树。如果存在,返回 true ;否则,返回 false 。
class Solution {
public:
bool isSubtree(TreeNode* root, TreeNode* subRoot) {
if (root == nullptr) return false; // 如果主树为空,不可能包含子树,返回false
if (subRoot == nullptr) return true; // 如果子树为空,空树被认为是任何树的子树,返回true
// 检查当前节点的树与子树是否相同,或者子树是否存在于左子树或右子树中
return sameTree(root, subRoot) || isSubtree(root->left, subRoot) || isSubtree(root->right, subRoot);
}
bool sameTree(TreeNode* root, TreeNode* subRoot) {
if (root == nullptr || subRoot == nullptr) return root == subRoot; // 如果任一树为空,只有当两者都为空时返回true
// 检查当前节点的值是否相同,并且递归检查左右子树
return root->val == subRoot->val && sameTree(root->left, subRoot->left) && sameTree(root->right, subRoot->right);
}
};
9.对称二叉树
给一个二叉树的根节点,检查它是否轴对称
判断两棵树是否镜像对称,只要判断两棵子树都是镜像对称的就行了。如果用迭代的方式,可以使用 BFS 层序遍历,把每一层的节点求出来,然后用左右双指针判断每一层是否是对称的。
class Solution {
public:
bool isSymmetric(TreeNode* root) {
if(root == nullptr) return true;
return check(root->left, root->right);
}
bool check(TreeNode* left, TreeNode* right){
if(left == nullptr || right == nullptr) return left == right;
if(left->val != right->val) return false;
return check(left->right, right->left) && check(left->left, right->right);
}
};