代码随想录第九天|二叉树(2)

目录

LeetCode 226. 翻转二叉树

LeetCode 101. 对称二叉树

LeetCode 104. 二叉树的最大深度 111. 二叉树的最小深度

LeetCode 110. 平衡二叉树

LeetCode 257. 二叉树的所有路径

LeetCode 404. 左叶子之和

LeetCode 222. 完全二叉树的节点个数

总结


LeetCode 226. 翻转二叉树

题目链接:LeetCode 226. 翻转二叉树

思想:本题非常简单,要翻转一个二叉树,只需要在遍历过程中,把当前节点的左右节点交换一下位置就完成啦。

代码如下:

    void bianli(TreeNode* cur){
        if (!cur) return;
        TreeNode* temp = cur->left;
        cur->left = cur->right;
        cur->right = temp;
        bianli(cur->left);
        bianli(cur->right);
    }

    TreeNode* invertTree(TreeNode* root) {
        bianli(root);
        return root;
    }

LeetCode 101. 对称二叉树

题目链接:LeetCode 101. 对称二叉树

思想:二叉树的题目普遍涉及到遍历,所以每一题都要思考要采取怎么样的遍历方式才适合本题。很明显,本题需要判断一个二叉树的对称性,就必须两个左右节点同时进行比较,那么就需要左右连着一起的一个遍历方式,那么只能采取后序遍历,左右中了。同时遍历左子树,采取左右中;遍历右子树,采取右左中。这样才能对上对称性。同时需要把左右子树的对称性作为返回值,所以前序遍历也不行。

最后,需要明确不对称的情况:

  1. 左子树的节点存在,右子树的节点为空;
  2. 左子树的节点为空,右子树的节点存在;
  3. 左右子树的节点都存在,但值不同;

还需要明确一种情况就是:两个节点都不存在那么就是对称的。

代码如下:

    bool compare(TreeNode* left, TreeNode* right){
        if (left == NULL && right != NULL) return false;
        else if (left != NULL && right == NULL) return false;
        else if (left == NULL && right == NULL) return true;
        else if (left->val != right->val) return false;

        bool inside = compare(left->right, right->left);
        bool outside = compare(left->left, right->right);
        return inside && outside;
    }

    bool isSymmetric(TreeNode* root) {
        if (!root) return true;
        return compare(root->left, root->right);
    }

LeetCode 104. 二叉树的最大深度 111. 二叉树的最小深度

题目链接:LeetCode 104. 二叉树的最大深度LeetCode 111. 二叉树的最小深度

思想:可以采取昨天的层序遍历方法,最大深度就遍历到低,最小深度就遍历到第一个叶子结点,也就是说第一个没有左右节点的节点。所以这里就不过多赘述。

LeetCode 110. 平衡二叉树

题目链接:LeetCode 110. 平衡二叉树

思想:本题确实有点坑,我最开始以为是左右子树的深度不超过一,结果是所有节点之间的深度不超过一。所以这里我们再过一遍概念。

  • 二叉树节点的深度:指从根节点到该节点的最长简单路径边的条数。
  • 二叉树节点的高度:指从该节点到叶子结点的最长简单路径边的条数。

很明显,求深度要从上到下查,所以需要前序遍历,而高度只能从下到上查,所以只能后序遍历。但深度和高度是一个相对概念,深度大,高度小;深度小,高度大。所以两个节点之间深度不超过一,也可以转换成两个节点之间高度不超过一。所以主要就是求当前节点的左右子树的高度,如果左右子树高度之差小于等于1就返回当前二叉树的高度。

代码如下:

    int getDepth(TreeNode* cur){
        if (!cur) return 0;
        int leftDepth = getDepth(cur->left);
        if (leftDepth == -1) return -1;
        int rightDepth = getDepth(cur->right);
        if (rightDepth == -1) return -1;
        return abs(rightDepth - leftDepth) > 1 ? -1 : 1 + max(rightDepth, leftDepth);
    }

    bool isBalanced(TreeNode* root) {
        return getDepth(root) == -1 ? false : true;
    }

LeetCode 257. 二叉树的所有路径

题目链接:LeetCode 257. 二叉树的所有路径

思想:这道题目要求从根节点到叶子的路径,所以需要前序遍历,这样才方便让父节点指向孩子节点,找到对应的路径。在这道题目中将第一次涉及到回溯,因为我们要把路径记录下来,需要回溯来回退一个路径再进入另一个路径。

首先,我们需要往参数里放根节点,存放需要回溯节点的数组以及用来返回最终结果的数组。其次,本题的终止条件是找到叶子结点就开始处理。处理的逻辑就是,new一个string,然后遍历用于回溯的数组,将里面的值拼接成“x->x->x”的样子即可。接下来就是要遍历左右节点了,如果左右节点存在的话就继续遍历,并在遍历结束之后将回溯数组的最后元素弹出即可,达成回溯的效果。

代码如下:

    void rootPathtoLeef(TreeNode* cur, vector<int>& path, vector<string>& result){
        path.push_back(cur->val);
        if (cur->left == NULL && cur->right == NULL){
            string str = "";
            for (int i = 0; i < path.size() - 1; i++){
                str += to_string(path[i]);
                str += "->";
            }
            str += to_string(path[path.size() - 1]);
            result.push_back(str);
            return;
        }
        if (cur->left){
            rootPathtoLeef(cur->left, path, result);
            path.pop_back();
        }
        if (cur->right){
            rootPathtoLeef(cur->right, path, result);
            path.pop_back();
        }
    }  
    vector<string> binaryTreePaths(TreeNode* root) {
        vector<int> path;
        vector<string> result;
        if (!root) return result;
        rootPathtoLeef(root, path, result);
        return result;
    }

LeetCode 404. 左叶子之和

题目链接:LeetCode 404. 左叶子之和

思想:竟然有404的题目,不应该找不到吗?哈哈哈哈,开个玩笑。本题也特别简单,就判断左叶子就行了。如何判断左叶子就需要父亲节点才行。所以这个稍微带来点麻烦。

代码如下:

    void bianli(TreeNode* cur, int& sum){
        if (!cur) return;
        if (cur->left && cur->left->left == NULL && cur->left->right == NULL){
            sum += cur->left->val;
            bianli(cur->left, sum);
        }
        if (cur->left) bianli(cur->left, sum);
        if (cur->right) bianli(cur->right, sum);
    }
    int sumOfLeftLeaves(TreeNode* root) {
        if(!root) return 0;
        int sum = 0;
        bianli(root, sum);
        return sum;
    }

LeetCode 222. 完全二叉树的节点个数

题目链接:LeetCode 222. 完全二叉树的节点个数

思想:本题可以用普通版的遍历,采用O(n)的时间复杂度就能数清楚每种树的节点,包含完全二叉树。那既然这样,为什么这题不叫二叉树的节点个数呢。所以这题可以采用另一些方法来数。

完全二叉树里面,又可以分为很多个小的满二叉树,所以可以通过数里面有多少个满二叉树来降低时间复杂度。如果目前节点下的子树不是满二叉树,就递归其左右孩子,直到遇到满二叉数为止,然后用2^树深度-1计算满二叉树的节点个数。

代码如下:

    int countNodes(TreeNode* root) {
        if (!root) return 0;
        int leftDepth = 0;
        int rightDepth = 0;
        TreeNode* curLeft = root->left;
        TreeNode* curRight = root->right;
        while (curLeft){
            curLeft = curLeft->left;
            leftDepth++;            
        }
        while (curRight){
            curRight = curRight->right;
            rightDepth++;
        }
        if (leftDepth == rightDepth){
            return (2 << leftDepth) - 1;
        }
        return countNodes(root->left) + countNodes(root->right) + 1;
    }

时间复杂度:O(logn*logn),空间复杂度:O(logn)。

总结

二叉树总要涉及到各种遍历的方式,采取正确的遍历方式和终止条件是无比重要的。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值