【代码随想录】刷题Day17

文章介绍了如何使用后序遍历判断AVL树的平衡状态,以及通过前序遍历获取二叉树的所有路径。同时,展示了计算左叶子节点之和的方法。对于空间优化,提出了将字符串参数改为引用以减少内存消耗的策略。
摘要由CSDN通过智能技术生成

1.AVLTree判断

110. 平衡二叉树

后序遍历的强化理解:

所谓后续遍历,不仅仅是一种遍历,其实它是完成了所有左右子树的递归。后续遍历能将自己所求的值返回给上层节点。这在比较中很关键,举个例子,我们能得到下边节点返回给上面节点的层数,那么就能进行高度的比较。

本题其实也是一样的思路:

1.我想设计一个算法,使得每一个节点的高度,那么后续遍历能完成该任务。是否平衡的比较落在左右节点之差上,最后如果不是AVL树,那我们返回-1。

2.返回值为int型,因为我们需要统计每一层的节点高度;传入的参数为树的节点

3.结束递归依据为root是否走到nullptr,如果根节点为空,此时走到底部,返回给上层为0,因为该位置没有节点

4.我们使用后续遍历,那么对应的定义left变量接收左边的高度,并且如果左边高度为-1,说明此时下面传回的信息是“已经不是平衡二叉树”,那么后续其实已经不需要操作了,那么我们直接返回-1,往上告知该树不是平衡二叉树;对应的定义right变量接收右边的高度,遇到-1的情况与左子树一样处理。

5.最后我们执行中间操作:如果左边-右边的绝对值绝对高度差大于1,说明此时不平衡,直接返回-1;如果不是,那么我们要返回上层的高度,所以我们要比较左右节点高度谁大,将大的值进行加一再返回,加一操作是因为上层节点也是一个高度,所以上层得到自己的高度是下面高度加上自己节点的高度。

class Solution {
public:
    int _isBalancedR(TreeNode* root)
    {
        if(root==nullptr)
            return 0;
        int left = _isBalancedR(root->left);
        if(left==-1)
            return -1;
        int right = _isBalancedR(root->right);
        if(right==-1)
            return -1;
        int ret;
        if(abs(left-right)>1)
            return -1;
        return ret=(left>right)?left+1:right+1;
    }
    bool isBalanced(TreeNode* root) {
        if(_isBalancedR(root)==-1)
            return false;
        return true;
    }
};

2.二叉树的所有路径

257. 二叉树的所有路径

大体思路:我想通过传递string的变量,使得每一层都有不同的string继承上面传来的路径

1.实现该函数传入的参数为:根节点,引用参数vector<string> vs和string s,由于我们只需要对s收获的路径存储到引用vs中,所以不需要进行什么传回操作,因此我们函数返回void

2.返回条件,这题与之前的最小深度思路有点重合:”就是如果一个节点左右有一个节点为空,但是另一个不为空,此时往空节点那里走是不会触发存储条件的!!!这点很重要,是树的减枝操作“;所以我们不仅要判断节点是否为空,还要判断节点的左右节点是否为空。因此返回条件有两种:一、如果当前节点不为空,但是左右节点为空,说明该节点为叶子节点,那么我们需要把这个路径存储下来,再返回  二、如果当前节点为空,此时已经过了条件一的判断,说明这种路径是需要被减枝的,所以直接返回即可

3.我们使用的是前序遍历,因为这样我们才能得到遍历的叶子节点数据,那操作很简单:就是将root的val存储到s中,随后左右遍历

4.s中存储数据需要注意,如果是中间操作,那么我们要加上题目要求的”->“标记,如果在叶子节点,那么说明此时不需要加”->“标记

class Solution {
public:
    void _GetTreePathR(TreeNode* root,vector<string>& vs,string s)
    {
        if(root&&root->left==nullptr&&root->right==nullptr)
        {
            s+=(to_string(root->val));
            vs.push_back(s);
            return;
        }
        if(root==nullptr)
            return;
        s+=(to_string(root->val)+"->");
        _GetTreePathR(root->left,vs,s);
        _GetTreePathR(root->right,vs,s);
    }
    vector<string> binaryTreePaths(TreeNode* root) {
        vector<string> vs;
        string s;
        _GetTreePathR(root,vs,s);
        return vs;
    }
};

这种通过string临时遍历保存每一层的操作确实简单,但是它浪费空间啊,每一层都保存一个string,要是节点多,爆内存是迟早的事情。所以优化的目标就是把string也变成引用参数,这样我们开辟的就只有一个string了。不过此时对应的就是要把sting往上返回时,减去一些数据。

无非就是用一个tmp存储,在走到vs存储后,将s剪掉后面的数据;当一层遍历结束,返回上层时,把对应的数据删除

class Solution {
public:
    void _GetTreePathR(TreeNode* root,vector<string>& vs,string& s)
    {
        if(root&&root->left==nullptr&&root->right==nullptr)
        {
            string tmp = to_string(root->val);
            s+=(tmp);
            vs.push_back(s);
            s.erase(s.end()-tmp.size(),s.end());
            return;
        }
        if(root==nullptr)
            return;
        string tmp = to_string(root->val)+"->";
        s+=(tmp);
        _GetTreePathR(root->left,vs,s);
        _GetTreePathR(root->right,vs,s);
        s.erase(s.end()-tmp.size(),s.end());
    }
    vector<string> binaryTreePaths(TreeNode* root) {
        vector<string> vs;
        string s;
        _GetTreePathR(root,vs,s);
        return vs;
    }
};

3.左叶子之和

404. 左叶子之和

这道题所说的左叶子特征:

1.该节点没有左右节点

2.该节点为父节点的左节点

所以描述成代码就是:当前位置不为空,当前位置的左节点不为空,当前位置的左节点没有子节点

class Solution {
public:
    void _GetSumR(TreeNode* root,int& sum)
    {
        if(root&&root->left&&!(root->left->left)&&!(root->left->right))
            sum+=root->left->val;
        if(root==nullptr)
            return;
        _GetSumR(root->left,sum);
        _GetSumR(root->right,sum);
    }
    int sumOfLeftLeaves(TreeNode* root) {
        int sum = 0;
        _GetSumR(root,sum);
        return sum;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

灼榆

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值