寒假刷题打卡第九天 | 树

  1. 二叉树的深度
    这是剑指offer上的原题。用递归的方式很快写出如下代码,但是,速度很慢。
class Solution {
public:
    int maxDepth(TreeNode* root) {
        if(root == nullptr)
            return 0;
        if(!root->left && (!root->right))
            return 1;
        return 1 + max(maxDepth(root->left), maxDepth(root->right));
    }
};

用队列来BFS,然后记录层数,仍然一样的慢。。。

class Solution {
public:
    int maxDepth(TreeNode* root) {
        if(!root)
            return 0;
        queue<TreeNode*> q;
        int level=0;//这个地方容易错误的初始化为1. 实际上是dangyic
        int curLevel = 1;
        int nextLevel = 0;
        q.push(root);
        while(q.size())
        {
            if(q.front()->left)
            {
                q.push(q.front()->left);
                nextLevel++;
            }
            if(q.front()->right)
            {
                q.push(q.front()->right);
                nextLevel++;
            }
            q.pop();
            curLevel--;
            if(!curLevel)
            {
                curLevel=nextLevel;
                nextLevel=0;
                level++;
            }
        }
        return level;
    }
};

看了答案,其实第一种方法就是DFS。
2. 平衡树
在上一题的思路下,很容易想到递归遍历每个节点,求出每个节点的深度。判断是否平衡。
于是容易得到下面的代码:

class Solution {
public:
    int height(TreeNode* root)
    {
        if(!root)
            return 0;
        int leftHeight = height(root->left);
        int rightHeight = height(root->right);
        return max(leftHeight, rightHeight)+1;
    }
    bool isBalanced(TreeNode* root) {
        if(!root)
            return true;
        return abs(height(root->right)-height(root->left))<=1 && isBalanced(root->right) && isBalanced(root->left);
    }
};

但是实际上,如果以某个节点为root的子树不是平衡树,那么我们不必知道它的深度,可以直接返回-1.

class Solution {
public:
    int height(TreeNode* root)
    {
        if(!root)
            return 0;
        int leftHeight = height(root->left);
        int rightHeight = height(root->right);
        if(leftHeight==-1 || rightHeight==-1 || abs(leftHeight-rightHeight)>1)
            return -1;
        return max(leftHeight, rightHeight)+1; //别忘了+1,嘤嘤嘤
    }
    bool isBalanced(TreeNode* root) {
        return height(root) >= 0;
    }
};
  1. 二叉树的直径
    遍历每个节点,每个节点的直径等于其左右子树的高度之和。维护一个最大直径指针,将每个节点的直径与直径的最大值作比较,并更新最大直径。
class Solution {
public:
    int diameterOfBinaryTree(TreeNode* root) {
        int res=0;
        int* maxDiameter=&res;
		//愚蠢的我最开始的写法竟然是:int* maxDiameter=0;
        diameterOfBinaryTreeCore(root, maxDiameter);
        return *maxDiameter;
    }
    void diameterOfBinaryTreeCore(TreeNode* root, int* maxDiameter)
    {
        if(!root)
            return;
        int leftHeight = height(root->left);
        int rightHeight = height(root->right);
        (*maxDiameter) = max(leftHeight + rightHeight, *maxDiameter);
        diameterOfBinaryTreeCore(root->left, maxDiameter);
        diameterOfBinaryTreeCore(root->right, maxDiameter);
    }
    int height(TreeNode* root)
    {
        if(!root)
            return 0;
        return max(height(root->left), height(root->right))+1;
    }
};

上面这种思路用了两个递归来实现,两个递归实际上可以合并为一个递归

class Solution {
public:
    int diameterOfBinaryTree(TreeNode* root) {
        int res=0;
        int* maxDiameter=&res;

        height(root, maxDiameter);
        return *maxDiameter;
    }
    int height(TreeNode* root, int* maxDiameter)
    {
        if(!root)
            return 0;
        int leftHeight = height(root->left,maxDiameter);
        int rightHeight = height(root->right, maxDiameter);
        (*maxDiameter) = max(leftHeight + rightHeight, *maxDiameter);
        //后序遍历,每个节点只访问一遍,所以,时间复杂度是O(n)
        return max(leftHeight, rightHeight) + 1;
    }
};

进一步优化,可以不单独维护一个maxHeight指针,直接定义为类的成员变量不就行了。
4. 翻转树
原题,略。
5. 并归两棵树
嘿嘿,应该只用了5min不到。
果然就是,写递归之前,首先想清楚递归的传递条件是什么。
以本题为例,两棵树的并归,等价于根节点求和,左子树与左子树并归、右子树与右子树并归。

class Solution {
public:
    TreeNode* mergeTrees(TreeNode* root1, TreeNode* root2) {
        if(!root1)
            return root2;
        if(!root2)
            return root1;
        root1->val += root2->val;
        root1->left = mergeTrees(root1->left, root2->left);
        root1->right = mergeTrees(root1->right, root2->right);
        return root1;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值