思路:以X为根的树怎么得到结果,然后讨论可能性,需要哪些信息,然后创建信息类
模板:获取左子树的信息,获取右子树的信息,然后得到自己的信息
110. 平衡二叉树
平衡二叉树:左子树为平衡二叉树,右子树为平衡二叉树,左右子树高度差绝对值小于等于1
当判断以X为根的树是否为平衡二叉树时,需要三类信息,就是以上所列的,因此可以额外设计一个类,保存三类信息
class Info{
public:
bool isBlance;
int height;
Info(bool isBlance,int height):isBlance(isBlance),height(height){}
};
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
class Info{
public:
bool isBlance;
int height;
Info(bool isBlance,int height):isBlance(isBlance),height(height){}
};
Info* process(TreeNode* root){
if(root==nullptr){//空树是平衡二叉树
return new Info(true,0);
}
Info* leftInfo=process(root->left);
Info* rightInfo=process(root->right);
bool isBlance=true;//以root为根结点的树
//满足下面3个if条件的任何一个,则该树就是平衡二叉树
if(!leftInfo->isBlance){
isBlance=false;
}
if(!rightInfo->isBlance){
isBlance=false;
}
if(abs(leftInfo->height - rightInfo->height)>1){
isBlance=false;
}
int height=max(leftInfo->height,rightInfo->height)+1;//该树的高度
return new Info(isBlance,height);
}
bool isBalanced(TreeNode* root) {
return process(root)->isBlance;
}
};
分析:二叉搜索树的判断逻辑:
- 左子树为二叉搜索树
- 右子树为二叉搜索树
- 根节点的值大于左子树的最大值
- 根节点的值下于右子树的最小值
满足以上条件的就是二叉搜索树。所以需要知道左右子树的相关信息
class Info{
public:
bool isSearch;
int maxVal;
int minVal;
Info(bool isSearch,int maxVal,int minVal):isSearch(isSearch),maxVal(maxVal),minVal(minVal){}
};
就是用来保存左右子树的相关信息
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
class Info{
public:
bool isSearch;
int maxVal;
int minVal;
Info(bool isSearch,int maxVal,int minVal):isSearch(isSearch),maxVal(maxVal),minVal(minVal){}
};
Info* process(TreeNode* root){
if(root==nullptr){//空树直接返回空
return nullptr;
}
Info* leftInfo=process(root->left);//获得左子树的相关信息
Info* rightInfo=process(root->right);//获得右子树的相关信息
bool isSearch=true;
int maxVal=root->val;
int minVal=root->val;
//判断逻辑
if(leftInfo!=nullptr && !leftInfo->isSearch){
isSearch=false;
}
if(rightInfo!=nullptr && !rightInfo->isSearch){
isSearch=false;
}
if(leftInfo!=nullptr && root->val<=leftInfo->maxVal){
isSearch=false;
}
if(rightInfo!=nullptr && root->val>=rightInfo->minVal){
isSearch=false;
}
//求本树的最大值和最小值
if(leftInfo!=nullptr && leftInfo->maxVal>maxVal){
maxVal=leftInfo->maxVal;
}
if(rightInfo!=nullptr && rightInfo->maxVal>maxVal){
maxVal=rightInfo->maxVal;
}
if(leftInfo!=nullptr && leftInfo->minVal<minVal){
minVal=leftInfo->minVal;
}
if(rightInfo!=nullptr && rightInfo->minVal<minVal){
minVal=rightInfo->minVal;
}
return new Info(isSearch,maxVal,minVal);
}
bool isValidBST(TreeNode* root) {
return process(root)->isSearch;
}
};
求二叉树的最大距离,即路径的最大节点数
分析:假设要求以X节点为根的树的最大距离。
有三种情况:
- 最大距离在左子树上
- 最大距离在右子树上
- 最大距离经过X节点,即左子树的高度+右子树的高度+1
所以本题需要知道左子树的相关信息和右子树的相关信息
因此需要构建Info类
class Info {
public:
int largestDis;//最大距离
int height;//高度
Info(int largestDis,int height):largestDis(largestDis),height(height){}
};
Info* process(Node* root) {//返回以root为根的树的相关信息
if (root == NULL) {
return new Info(0, 0);
}
Info* leftInfo = process(root->left);
Info* rightInfo = process(root->right);
//三种可能性
int p1 = leftInfo->largestDis;
int p2 = rightInfo->largestDis;
int p3 = leftInfo->height + rightInfo->height + 1;
int height = max(leftInfo->height, rightInfo->height) + 1;
return new Info(max(p1, p2, p3), height);
}
int largetDis(Node* root) {
process(root)->largestDis;
}
判断一棵树是否为满二叉树
分析:假设判断以X为根的二叉树是否为满二叉树
如果二叉树的节点数等于2h -1,(h为二叉树的高度),则该树为满二叉树。
要得到二叉树的节点数,需要知道左子树的节点数和右子树的节点数
要得到二叉树的高度,需要知道左子树的高度和右子树的高度。
所以信息类Info
class Info {
public:
int nodeSum;
int height;
Info(int nodeSum,int height):nodeSum(nodeSum),height(height){}
};
Info* process(Node* root) {
if (root == NULL) {
return new Info(0, 0);
}
Info* leftInfo = process(root->left);
Info* rightInfo = process(root->right);
int nodeSum = leftInfo->nodeSum + rightInfo->nodeSum + 1;
int height = max(leftInfo->height, rightInfo->height) + 1;
return new Info(nodeSum, height);
}
bool isFullBinaryTree(Node* root) {
int height = process(root)->height;
int nodeSum = process(root)->nodeSum;
return nodeSum == pow(2, height) - 1;
}
分析可能性:1 最大搜索子树在左子树上
2 最大搜索子树在右子树上
3 最大搜索子树就是本身
对于情况3,需要满足左子树为搜索二叉树,右子树也为搜索二叉树,左子树的最大值小于根结点的值,右子树的最小值大于根结点的值
所以信息类
class Info {
public:
int maxBSTSize;//最大二叉搜索子树中结点的个数
int allSize;//树的总个数
int max;//最大值
int min;//最小值
};
#include<iostream>
#include<unordered_map>
using namespace std;
class Info {
public:
int maxBSTSize;//最大二叉搜索子树中结点的个数
int allSize;//树的总个数
int max;//最大值
int min;//最小值
Info(int maxBSTSize, int allSize, int max, int min) :maxBSTSize(maxBSTSize), allSize(allSize), max(max), min(min) {
}
};
class Node {
public:
int val;
Node* left;
Node* right;
Node(int val):val(val) {
left = NULL;
right = NULL;
}
};
Info* process(Node* root) {
if (root == NULL) {
return NULL;
}
int max = root->val;
int min = root->val;
int maxBSTSize = 0;
int allSize = 1;
Info* leftInfo = process(root->left);
Info* rightInfo = process(root->right);
if (leftInfo) {
max = leftInfo->max > max ? leftInfo->max : max;
min= leftInfo->min < min ? leftInfo->min : min;
allSize += leftInfo->allSize;
}
if (rightInfo) {
max = rightInfo->max > max ? rightInfo->max : max;
min = rightInfo->min < min ? rightInfo->min : min;
allSize += rightInfo->allSize;
}
int p1 = -1;//情况1,最大搜索子树在左子树
if (leftInfo != NULL) {
p1 = leftInfo->maxBSTSize;
}
int p2 = -1;//情况2,最大搜索子树在右子树
if (rightInfo != NULL) {
p2 = rightInfo->maxBSTSize;
}
int p3 = -1;//情况3
bool leftIsBST = leftInfo == NULL ? true : (leftInfo->allSize == leftInfo->maxBSTSize);//左子树是否为二叉搜索树
bool rightIsBST = rightInfo == NULL ? true : (rightInfo->allSize == rightInfo->maxBSTSize);
bool isBST = true;
if (leftInfo) {
if (leftInfo->max >= root->val) {
isBST = false;
}
}
if (rightInfo) {
if (rightInfo->min <= root->val) {
isBST = false;
}
}
if (leftIsBST && rightIsBST && isBST) {//该树为二叉搜索树
int leftSize = leftInfo == NULL ? 0 : leftInfo->allSize;
int rightSize = rightInfo == NULL ? 0 : rightInfo->allSize;
p3 = leftSize + rightSize + 1;
}
maxBSTSize = std::max(p1, std::max(p2, p3));
return new Info(maxBSTSize, allSize, max, min);
}
int maxBstSize(Node* root) {
if (root == NULL) {
return 0;
}
return process(root)->maxBSTSize;
}
void print(Node* root) {
if (root == NULL) {
return;
}
print(root->left);
cout << root->val << " ";
print(root->right);
}
int main() {
int n, root;
unordered_map<int, Node*>nodes;
cin >> n >> root;
nodes.emplace(root, new Node(root));
for (int i = 0; i < n; ++i) {
int fa, lch, rch;
cin >> fa >> lch >> rch;
Node* head = nodes[fa];
if (lch == 0) {
head->left = NULL;
}
else {
Node* leftNode = new Node(lch);
nodes.emplace(lch, leftNode);
head->left = leftNode;
}
if (rch == 0) {
head->right = NULL;
}
else {
Node* rightNode = new Node(rch);
nodes.emplace(rch, rightNode);
head->right = rightNode;
}
}
Node* head = nodes[root];
cout << maxBstSize(head);
return 0;
}
判断是否为完全二叉树
以某个结点为根的树列可能性:
1 左子树为满二叉树,右子树为满二叉树,左右子树高度一样,则为完全二叉树
2 左子树为完全二叉树,右子树为满二叉树,左子树高度等于右子树高度+1
3 左子树为满二叉树,右子树为满二叉树,左子树高度等于右子树高度+1
4 左子树为满二叉树,右子树为完全二叉树,左子树高度等于右子树高度
以上4中情况满足一个即为完全二叉树。
要想判断该树是否为完全二叉树,需要知道子树是否为满二叉树,是否为完全二叉树,子树的高度
信息类:
class Info {
public:
bool isFull;
bool isCBT;
int height;
Info(bool isFull,bool isCBT,int height):isFull(isFull),isCBT(isCBT),height(height){}
};
class Info {
public:
bool isFull;
bool isCBT;
int height;
Info(bool isFull,bool isCBT,int height):isFull(isFull),isCBT(isCBT),height(height){}
};
class Node {
public:
int val;
Node* left;
Node* right;
Node(int val):val(val) {
left = NULL;
right = NULL;
}
};
Info* process(Node* root) {
if (root == NULL) {
return new Info(true, true, 0);
}
Info* leftInfo = process(root->left);
Info* rightInfo = process(root->right);
bool isFull = leftInfo->isFull && rightInfo->isFull && leftInfo->height == rightInfo->height;
int height = max(leftInfo->height, rightInfo->height) + 1;
bool isCBT = false;
if (leftInfo->isFull && rightInfo->isFull && leftInfo->height == rightInfo->height) {
isCBT = true;
}
else if (leftInfo->isFull && rightInfo->isFull && leftInfo->height == rightInfo->height + 1) {
isCBT = true;
}
else if (leftInfo->isCBT && rightInfo->isFull && leftInfo->height == rightInfo->height + 1) {
isCBT = true;
}
else if (leftInfo->isFull && rightInfo->isCBT && leftInfo->height == rightInfo->height) {
isCBT = true;
}
return new Info(isFull, isCBT, height);
}
bool isCBTree(Node* root) {
return process(root)->isCBT;
}
给定一个头结点head,和另外两个结点a和b,返回a和b的最低公共祖先
思路:以X结点为根的树,返回a和b的最低公共祖先
1 X不是最低公共祖先
①左子树上有答案
②右子树上有答案
③X这棵树没有a或者没有b,即没有答案
2 X是最低公共最先
①左子树有a或者b,右子树有另外一个
②X就是a,左子树或右子树上有b
③X就是b,左子树或者右子树上有a
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
class Info {
public:
bool findA;
bool findB;
TreeNode* ans;
Info(bool findA,bool findB,TreeNode* ans):findA(findA),findB(findB),ans(ans){
}
};
Info* process(TreeNode* root, TreeNode* a, TreeNode* b) {
if (root == NULL) {
return new Info(false, false, NULL);
}
Info* leftInfo = process(root->left, a, b);
Info* rightInfo = process(root->right, a, b);
bool findA = (root == a) || leftInfo->findA || rightInfo->findA;
bool findB = (root == b) || leftInfo->findB || rightInfo->findB;
TreeNode* ans = NULL;
if (leftInfo->ans != NULL) {
ans = leftInfo->ans;
}
else if (rightInfo->ans != NULL) {
ans = rightInfo->ans;
}
else {
if (findA && findB) {
ans = root;
}
}
return new Info(findA, findB, ans);
}
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
return process(root, p, q)->ans;
}
};
派对的最大快乐值
题目描述:一个员工只有一个直接上级。也就是这个公司员工的层级结构就是一个多叉树。
现在公司邀请员工参加派对,要求不能同时邀请员工和员工的任一下级(即直接上下级不能同时邀请),如何邀请员工,才能使得参加派对的员工的快乐值是所有情况中最大的。最后返回最大的快乐值。
员工的定义如下:
class Employee {
public:
int happy;
vector<Employee*>nexts;
Employee(int happy):happy(happy){}
};
思路:以x为根结点树,返回最大的快乐值
情况1 x来的话,返回最大值
最大值=x的快乐值+所有后代不来的最大值
情况2 x不来的话,返回最大值
最大值=所有后代来的最大值和不来的最大值最大的加起来
#include<iostream>
#include<vector>
using namespace std;
class Employee {
public:
int happy;
vector<Employee*>nexts;
Employee(int happy):happy(happy){}
};
class Info {
public:
int yes;
int no;
Info(int yes,int no):yes(yes),no(no){}
};
Info* process(Employee* root) {
if (root == NULL) {
return new Info(0, 0);
}
int yes = root->happy;
int no = 0;
for (Employee* e : root->nexts) {
Info* next = process(e);
yes += next->no;
no += max(next->yes, next->no);
}
return new Info(yes, no);
}
int maxVal(Employee* root) {
Info* allInfo = process(root);
return max(allInfo->yes, allInfo->no);
}
int main() {
return 0;
}