代码随想录 二叉树部分算法

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);
    }
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值