随想录训练营15/60 | LC 110.平衡二叉树;LC 257. 二叉树的所有路径;LC 404.左叶子之和

LC 110.平衡二叉树

题目链接LC 110.平衡二叉树
思路:如何判断一个二叉树是否平衡?看节点是否都满足左右子树的高度差不超过2,若满足则为平衡二叉树,否则为不平衡二叉树,计算高度一般使用的是后序遍历
本题的思路为:(递归三步)
函数参数和返回值:参数为节点地址,返回值为以输入节点为根节点的树的高度(必须要知道高度,否则无法判断是否平衡),若树不平衡则直接返回-1,无需返回树的高度。
终止(返回)条件:当节点遇到空节点返回0,表示树高为0。
单层递归逻辑:如何判断当前节点是否为平衡二叉树?判断该节点的左右子树高度的差值。若左右子树本身就不平衡,就直接不平衡。然后判断差是否大于等于2,若满足,则也不平衡;若平衡,就返回该节点的高度,也就是左右子树高度取大值加一。平衡就返回高度,不平衡就返回-1。
代码

/**
 * 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:
    //输入是遍历到的节点
    //输出是若平衡,节点为根节点的高度;若不平衡,则为-1
    int getHeight(TreeNode* cur){
        if(cur==nullptr)return 0;//为空节点则返回0

        int leftHeight = getHeight(cur->left);
        if(leftHeight==-1)return -1;

        int rightHeight = getHeight(cur->right);
        if(rightHeight==-1)return -1;

        if(abs(rightHeight-leftHeight)>1)return -1;
        
        return 1+max(rightHeight, leftHeight);
    }
    bool isBalanced(TreeNode* root) {
        int result = getHeight(root);
        if(result==-1)return false;
        else return true;
    }
};

LC 257. 二叉树的所有路径

题目链接LC 257. 二叉树的所有路径
思路:需要保存从根节点到叶子节点的路径,因此使用前序遍历回溯。回溯和递归是一家子,有递归必定有回溯。
递归三步:
递归参数和返回值:输入为遍历的节点地址和之前保存的结果,由于直接将结果保存,所以不用返回值
终止条件:当遇到叶子节点就终止,先保存叶子节点再终止,和之前不同,之前是遇到空节点再终止。
单层递归逻辑:先保存结果,然后分别进入左子树,右子树。
代码

/**
 * 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:
    void traversal(TreeNode* cur, vector<int>& path, vector<string>& result){//第二个输入是,保存路径,当有一条完整路径(到叶子节点)就将结果放到result中,并且进行回溯(删除后面的节点)
        path.push_back(cur->val);//中,因为到叶子节点就终止了,所以要把这部分写到终止条件前,为了让叶子节点也在path中,为了让回溯更优美,不然需要加入判断:当遇到叶子节点不能回溯
        //终止条件(不严格)
        //当节点为叶子节点时,就保存路径path
        if(cur->left==nullptr && cur->right==nullptr){
            string sPath;
            //先保存之前的
            for(int i=0; i<path.size()-1; i++){//注意不能用i<=path.size()-2,因为是无符号数-2就可能是无限大的数,可用int变量进行保存
                sPath += to_string(path[i]);
                sPath += "->";
            }
            //再保存叶子节点
            sPath += to_string(path[path.size()-1]);
            //将结果保存
            result.push_back(sPath);
            return;
        }
        //单层递归逻辑
        if(cur->left){
            traversal(cur->left, path, result);//当遇到叶子节点return后,需要把后面的节点弹出
            path.pop_back();//回溯,每个递归都要有对应的回溯
        }
        if(cur->right){
            traversal(cur->right, path, result);
            path.pop_back();
        }
    }
    vector<string> binaryTreePaths(TreeNode* root) {
        vector<string> result;
        vector<int> path;
        if(root==nullptr)return result;
        traversal(root, path, result);
        return result;
    }
};

LC 404.左叶子之和

题目链接LC 404.左叶子之和
思路:左叶子之和,不可以先判断是否是叶子,再判断是否为左叶子,因为左叶子只能通过父节点判断,因此需要注意要判断节点是否有左子树,然后判断左子树是否是叶子节点,如果是左子树叶子节点那么就取叶子节点的值
**为什么用后序遍历?**后序遍历递归参数值只需节点地址即可,前序遍历需要把左叶子值总和相加也传递到后面。
递归三部:
递归的参数和返回值:参数为节点地址,返回值为已知的左叶子节点值总和。
终止条件:当遍历到空节点返回的是0;当遍历到叶子节点返回的也是0;(?那我能不能只判断到叶子节点呢?)
单层递归逻辑:递归取左子树的左叶子之和,若左子树为叶子节点就取叶子节点的值;同样递归取右子树的左叶子之和,最终总和为左右子树的左叶子之和。
代码

/**
 * 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:
    //方案1
    int sumOfLeftLeaves(TreeNode* root) {
        if(root->left==nullptr && root->right==nullptr)return 0;
        int left=0;
        int right=0;
        //处理左子树
        if(root->left)left = sumOfLeftLeaves(root->left);//作用是对左子树进行递归遍历,返回值都为0,没什么实际意义
        //返回之后对叶子节点的父节点进行判断
        if(root->left!=nullptr && root->left->left==nullptr && root->left->right==nullptr && root)left = root->left->val;
        //处理右子树
        if(root->right)right = sumOfLeftLeaves(root->right);
        //左右子树的左叶子节点之和
        int sum = right + left;
        return sum;
    }
    //方案2
    int dfs(TreeNode* cur, bool isLeft){
        //当遇到空节点返回0;
        if(cur==nullptr)return 0;

        //不为空节点时,就判断是否是叶子节点
        int left = dfs(cur->left, true);
        int right = dfs(cur->right, false);
        if(cur->left==nullptr && cur->right==nullptr && isLeft){
            left = cur->val;
        }
        return left+right;
    }
    int sumOfLeftLeaves(TreeNode* root) {
        int result = dfs(root, false);
        return result;
    }

};

总结

通过这几天的实践,可以看出后序遍历在计算二叉树深度和节点高度时非常方便,前序遍历反而要考虑很多东西。当在统计二叉树的路径时,使用前序遍历比较合适。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值