1、平衡二叉树
https://leetcode.cn/problems/balanced-binary-tree/
注意算法采用的判断的方法
class Solution {
public:
//解题思路:
//遍历每一个节点,统计其左右子树的深度求差,绝对值<=1,则为true,否则返回false
//可采用后续递归 参数为根节点 中止条件节点为空返回真,或左右子树相差大于1
// bool getBalanced(TreeNode* cur){
// if(cur == nullptr) return true;
// int leftDepth = getBalanced(cur->left) //判断左子树是否平衡 并记录其深度
// bool leftBool = getBalanced(cur->left)
// int rightDepth = getBalanced(cur->right) //判断右子树是否平衡 并记录其深度
// bool rightBool = getBalanced(cur->right)
// //还要再写一个递归遍历的函数吗?可不可以直接唉循环中确定
// if(leftBool == false || rightBool == false) return false;
// return abs(leftDepth-rightDepth)<=1
// }
//单层逻辑: 计算节点左右子树的高度,若左右子树的高度大于1,则返回-1,
//否则返回节点的高度,以便于下次计算
//以节点高度表示是否平衡,为-1则代表不平衡,反之平衡
int getHigh(TreeNode* cur){
if(cur == nullptr) return 0;
//左节点返回高度
int leftHigh = getHigh(cur->left);
if(leftHigh == -1) return -1;
//右节点返回高度
int rightHigh = getHigh(cur->right);
if(rightHigh == -1) return -1;
//注意,当递归遍历时,可能某一个子节点不平衡 所以要加判定条件
//在哪加?首先若子节点不平衡,你们一定是左右节点的差大于1 返回-1 给上一节点
//也就是这个-1 是返回给leftHigh 或 rightHigh 所以要加判断,一遇到-1,就直接返回,
//因为子树不平衡,其上一节点肯定也不平衡
//当前节点的高度 1+最高的子树高度
if(abs(leftHigh-rightHigh)>1) return -1;
return 1+max(leftHigh,rightHigh);
}
bool isBalanced(TreeNode* root) {
int result = getHigh(root);
return result!=-1;
}
};
2.二叉树的所有路径
https://leetcode.cn/problems/binary-tree-paths/
class Solution {
public:
//因为要记录根节点到叶子节点的路径,所以要采用前序遍历:中左右 依次记录路径
void getRood(TreeNode*cur,vector<int>&path,vector<string>&result){
//2.中遍历 将遍历到的节点加入路径
path.push_back(cur->val);
//1.确定终止条件 遍历到根节点 则记录整个路径
if(cur->left == nullptr && cur->right == nullptr){
//把路径转化为字符串
string spath;
for(int i = 0;i<path.size()-1;i++){
spath += to_string(path[i]);
spath += "->";
}
spath += to_string(path[path.size()-1]);
//将此路径加入结果
result.push_back(spath);
return ;
}
//3.左遍历 左节点要存在
// if(cur->left){
// getRood(cur->left,path,result);
// }
// //4.右遍历
// if(cur->right){
// getRood(cur->right,path,result);
// }
//5.每次左右遍历后,要将path内的元素弹出,不然路径会一直增加
//先让其进行左右子树遍历,然后再弹出元素 回溯过程
//弹出的都是当前节点的子树节点
//修改3、4步
if(cur->left){
getRood(cur->left,path,result);
path.pop_back(); //弹出的都是当前节点的子树节点
}
if(cur->right){
getRood(cur->right,path,result);
path.pop_back();
}
}
vector<string> binaryTreePaths(TreeNode* root) {
vector<int> path;
vector<string> result;
if(root == nullptr) return result;
getRood(root,path,result);
return result;
}
};
3.左叶子之和
https://leetcode.cn/problems/sum-of-left-leaves/submissions/
class Solution {
public:
//解题思路:根据节点判断其左叶子节点,首先为叶子节点,其此为上一个节点的左子树
//可以采用后序遍历 左右中
//自写代码 部分错误 判定条件不对
// int getLeftSum(TreeNode*cur ,int& sum){
// //1.确定终止条件 为叶子节点时返回值
// if(cur->left == nullptr && cur->right == nullptr) return cur->val;
// int leftcoun = 0;
// int rightcoun = 0;
// if(cur->left) {
// leftcoun = getLeftSum(cur->left,sum);
// }
// if(cur->right){
// rightcoun = getLeftSum(cur->right,sum);
// }
// sum += leftcoun;
// //只接受左叶子节点的值
// return sum;
// }
//解题思路:根据节点判断其左叶子节点,首先为叶子节点,其此为上一个节点的左子树
//可以采用后序遍历 左右中
//判断当前节点是不是左叶子是无法判断的,必须要通过节点的父节点来判断其左孩子是不是左叶子
//该节点的左节点不为空,该节点的左节点的左节点为空,该节点的左节点的右节点为空,则找到了一个左叶子
//遍历时依然是遍历所有节点,但只将满足左叶子节点的值返回
int getLeftSum(TreeNode*cur ){
//1.确定终止条件
if(cur == nullptr) return 0; //节点为空
if(cur->left == nullptr && cur->right == nullptr) return 0; //节点为叶子节点
//只有节点为左叶子节点时,才返回值
int leftcoun = getLeftSum(cur->left); //左
//当前节点的左子树存在,且左子树为节点时
if(cur->left && cur->left->left == nullptr && cur->left->right == nullptr){//cur->left为叶子节点 且为cur的左叶子节点
leftcoun = cur->left->val;
}
int rightcoun = getLeftSum(cur->right); //右
int sum = leftcoun + rightcoun;
return sum;
}
//总结:
//因为是否为左叶子节点只能通过父节点来判断,而后序遍历会遍历所有节点
//所以,遇到节点为空、或节点为叶子节点都返回0
//而当遇到中间节点时,就判断其是否有左叶子节点,若有则返回
int sumOfLeftLeaves(TreeNode* root) {
return getLeftSum(root);
}
};
4.最后一行 最左侧节点的值
https://leetcode.cn/problems/find-bottom-left-tree-value/submissions/
class Solution {
public:
//思路:找到二叉树 最后一行 最左侧(第一个)叶子节点的值
//深度最大的一行 第一个叶子节点的值
//遍历记录高度或深度 存在左子树的大者的左叶子节点
// maxDepth result分别记录最大深度和最后一行的左侧叶子节点
//怎么确定最大深度?每一遍历向下一层时,depth++ 与当前记录的maxDeth做对比
//怎么确定是作业子节点?先遍历左子树,这样遍历到最后一行时,最左侧的叶子节点优先被记录,此后这一层的叶子节点深度都不大于记录的节点,不能被记录
int maxDepth = -1;
int result = 0;
void getLeftValue(TreeNode* cur,int depth){ //depth为该层的深度
//遍历至叶子节点 对该叶子节点的深度进行比较 大的话就更新maxDepth result
if(cur->left == nullptr && cur->right == nullptr){
if(depth>maxDepth){
result = cur->val;
maxDepth = depth;
}
}
//不需要对中节点进行操作 所以没有中节点的操作
//左
if(cur->left){
depth++; //要进入左子树 深度+1
getLeftValue(cur->left,depth);
depth--;//退出进入左子树 深度-1
}
//右
if(cur->right){
depth++;
getLeftValue(cur->right,depth);
depth--;
}
}
int findBottomLeftValue(TreeNode* root) {
getLeftValue(root,0);
return result;
}
};
5.路径总和
https://leetcode.cn/problems/path-sum/submissions/
class Solution {
public:
//目的:找到一个根节点,使含有其的路径之和为targetSum
//需要参数:根节点;sum 记录所遍历的路径之和
//当前节点为叶节点时,判断包含其在内的和是否与targetSum相等
// bool getRoodSum(TreeNode* cur,int& sum,int& targetSum){//初始sum为0
// //当前节点为叶节点时,判断包含其在内的和是否与targetSum相等
// if(cur->left == nullptr && cur->right == nullptr){
// if(targetSum - sum == cur->val) return true;
// }
// //当前节点不是叶子节点
// if(cur) sum += cur->val; //中
// //需要回溯
// bool leftBool = false;
// bool rightBool = false;
// if(cur->left) {
// leftBool = getRoodSum(cur->left,sum,targetSum);
// sum -= cur->left->val;
// }
// if(cur->right){
// rightBool = getRoodSum(cur->right,sum,targetSum);
// sum -= cur->right->val;
// }
// return leftBool||rightBool;
// }
//分析还是如上 加上三点:
//1.不用对中节点进行处理
//2.可以直接对targetSum进行减操作,看其是否为0
//3.满足条件返回时要注意如何返回
bool getRoodSum2(TreeNode* cur,int count){
//当前节点为叶节点时,判断包含其在内的和是否与targetSum相等
//当前节点为叶节点时,判断包含其在内的和是否与targetSum相等
if(!cur->left && !cur->right){
if(count == 0) return true;
else{
return false;
}
}
if(cur->left){
count -= cur->left->val;
if(getRoodSum2(cur->left,count)) return true; //上一个代码需要遍历所有,而 这一种只要需要满足的路径就返回
count += cur->left->val;
}
if(cur->right){
count -= cur->right->val;
if(getRoodSum2(cur->right,count)) return true; //上一个代码需要遍历所有,而 这一种只要需要满足的路径就返回
count += cur->right->val;
}
return false; //如果以上都不返回,则证明没有路径
}
bool hasPathSum(TreeNode* root, int targetSum) {
// int sum = 0;
if(root == nullptr) return false;
// return getRoodSum(root,sum,targetSum);
return getRoodSum2(root,targetSum-root->val);
}
};
6.从中序和后序遍历构造二叉树
https://leetcode.cn/problems/construct-binary-tree-from-inorder-and-postorder-traversal/submissions/
class Solution {
public:
TreeNode* traversal(vector<int>& inorder, vector<int>& postorder){
//1.若数组为空,则返回空
if(postorder.size() == 0) return nullptr;
//2.不为空,那么后序的最后一个为这棵树的根节点
TreeNode* root = new TreeNode(postorder[postorder.size()-1]);
//数组为1个节点时
if(postorder.size() == 1) return root;
//3.找切割点、分割中序
//因为inorder 和 postorder 都由 不同 的值组成,只需要在中序中找到根节点的值,即可分割中序的左右区间
//区间 采取左闭右开
int index = 0;
for(;index<inorder.size();index++){
if(inorder[index] == root->val) break;
}
//中序的左区间
vector<int> inorderleft(inorder.begin(),inorder.begin()+index);
//中序的右区间
vector<int> inorderright(inorder.begin()+index+1,inorder.end());
//后序的数目-1 因为最后一个元素为根节点 已经遍历过了
postorder.resize(postorder.size()-1);
//4.分割后序 因为后序左右中:根节点的左区间、根节点的右区间、根节点
//左区间的数目应该与中序的左区间的数目相同
vector<int> postorderleft(postorder.begin(),postorder.begin()+inorderleft.size());
vector<int> postorderright(postorder.begin()+inorderleft.size(),postorder.end());
//5.遍历左
root->left = buildTree(inorderleft,postorderleft);
//6.遍历右
root->right = buildTree(inorderright,postorderright);
return root;
}
TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
if (inorder.size() == 0 || postorder.size() == 0) return NULL;
return traversal(inorder,postorder);
}
};