代码随想录算法训练营Day16| 104. 二叉树的最大深度、559.n叉树的最大深度、111. 二叉树的最小深度、222. 完全二叉树的节点个数

代码随想录算法训练营Day16| 104. 二叉树的最大深度、559.n叉树的最大深度、111. 二叉树的最小深度、222. 完全二叉树的节点个数

104. 二叉树的最大深度

104. 二叉树的最大深度

而根节点的高度就是二叉树的最大深度。

①递归法

我们使用「左右中」的后序遍历方式求根节点的高度。

/**
 * 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:
    int maxDepth(TreeNode* root) {
        return searchMaxDepth(root);
    }

    int searchMaxDepth(TreeNode* node) {
        if (node == NULL) return 0;
        int leftDepth = searchMaxDepth(node->left);
        int rightDepth = searchMaxDepth(node->right);
        return max(leftDepth, rightDepth) + 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:
    int maxDepth(TreeNode* root) {
        queue<TreeNode*> que;
        if (root == NULL) return 0;
        else que.push(root);
        int res = 0;
        while (!que.empty()) {
            int size = que.size();
            res++; // 记录深度
            while (size--) {
                TreeNode* node = que.front();
                que.pop();
                if (node->left) que.push(node->left);
                if (node->right) que.push(node->right);
            }
        }
        return res;
    }
};

559.n叉树的最大深度

559. N 叉树的最大深度

将二叉树的情况推广到n叉树,思路类似。

①递归法

/*
// Definition for a Node.
class Node {
public:
    int val;
    vector<Node*> children;

    Node() {}

    Node(int _val) {
        val = _val;
    }

    Node(int _val, vector<Node*> _children) {
        val = _val;
        children = _children;
    }
};
*/

class Solution {
public:
    int maxDepth(Node* root) {
        return searchMaxDepth(root);
    }

    int searchMaxDepth(Node* node) {
        if (node == NULL) return 0;
        int maxDepth = 0;
        for (Node* child : node->children) {
            int tmp = searchMaxDepth(child);
            maxDepth = tmp > maxDepth ? tmp : maxDepth;
        }
        return maxDepth + 1;
    }
};

②迭代法

/*
// Definition for a Node.
class Node {
public:
    int val;
    vector<Node*> children;

    Node() {}

    Node(int _val) {
        val = _val;
    }

    Node(int _val, vector<Node*> _children) {
        val = _val;
        children = _children;
    }
};
*/

class Solution {
public:
    int maxDepth(Node* root) {
        queue<Node*> que;
        if (root == NULL) return 0;
        else que.push(root);
        int res = 0;
        while (!que.empty()) {
            int size = que.size();
            res++;
            while (size--) {
                Node* node = que.front();
                que.pop();
                for (Node* child : node->children) {
                    if (child) que.push(child);
                }
            }
        }
        return res;
    }
};

111. 二叉树的最小深度

111. 二叉树的最小深度

本题有一个误区,在处理节点的过程中,最大深度很容易理解,最小深度就不那么好理解,如图:

111.二叉树的最小深度

最小深度是从根节点到最近叶子节点的最短路径上的节点数量,注意终点是叶子节点。(左右孩子节点必须为空!)

①递归法

递归首先确定递归的三步骤:

  1. 确定递归函数的参数和返回值

参数为要传入的二叉树根节点,返回的是int类型的深度。代码如下:

int getDepth(TreeNode* node)
  1. 确定终止条件

终止条件也是遇到空节点返回0,表示当前节点的高度为0。代码如下:

if (node == NULL) return 0;
  1. 确定单层递归的逻辑

这块和求最大深度可就不一样了,一些同学可能会写如下代码:

int leftDepth = getDepth(node->left);
int rightDepth = getDepth(node->right);
int result = 1 + min(leftDepth, rightDepth);
return result;

如果这么求的话,没有左孩子的分支会算为最短深度。所以需要对左右孩子是否为空进行讨论

  • 所以,如果左子树为空,右子树不为空,说明最小深度是 1 + 右子树的深度。

  • 反之,右子树为空,左子树不为空,最小深度是 1 + 左子树的深度。 最后如果左右子树都不为空,返回左右子树深度最小值 + 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:
    int minDepth(TreeNode* root) {
        return getMinDepth(root);
    }

    int getMinDepth(TreeNode* node) {
        if (node == NULL) return 0;
        int leftDepth = getMinDepth(node->left);
        int rightDepth = getMinDepth(node->right);
        // 要考虑孩子节点为空的情况
        if (node->left == NULL && node->right != NULL) return rightDepth + 1;
        if (node->left != NULL && node->right == NULL) return leftDepth + 1;
        return min(leftDepth, rightDepth) + 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:
    int minDepth(TreeNode* root) {
        queue<TreeNode*> que;
        if (root == NULL) return 0;
        else que.push(root);
        int res = 0;
        while (!que.empty()) {
            int size = que.size();
            res++;
            while (size--) {
                TreeNode* node = que.front();
                que.pop();
                if (node->left == NULL && node->right == NULL) return res;
                if (node->left) que.push(node->left);
                if (node->right) que.push(node->right);
            }
        }
        return res;
    }
};

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

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

普通二叉树——递归法

首先按照普通二叉树的逻辑来求。

这道题目的递归法和求二叉树的深度写法类似, 而迭代法二叉树的层序遍历.html)遍历模板稍稍修改一下,记录遍历的节点数量就可以了。代码如下:

/**
 * 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:
    int countNodes(TreeNode* root) {
        return getNodeNum(root);
    }

    int getNodeNum(TreeNode* node) {
        if (node == NULL) return 0;
        int leftNum = getNodeNum(node->left);
        int rightNum = getNodeNum(node->right);
        return leftNum + rightNum + 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:
    int countNodes(TreeNode* root) {
        queue<TreeNode*> que;
        if (root == NULL) return 0;
        else que.push(root);
        int res = 0;
        while (!que.empty()) {
            int size = que.size();
            res += size;
            while (size--) {
                TreeNode* node = que.front();
                que.pop();
                if (node->left) que.push(node->left);
                if (node->right) que.push(node->right);
            }
        }
        return res;
    }
};

完全二叉树性质

首先我们需要熟悉完全二叉树的定义:完全二叉树的定义如下:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。

img

该定义表明,遍历一棵完全二叉树的左孩子节点,即可获得树根节点的深度。

int countDepth(TreeNode* node) {
        int depth = 0;
        while (node) {
            node = node->left;
            depth++;
        }
        return depth;
    }

另外还有些性质包括:

  • 满二叉树一共包含2^depth-1个节点

  • 若最底层为第 h 层,则该层包含 1~ 2^(h-1) 个节点。

  • 完全二叉树除最底层外,上层即为满二叉树

本题解法

完全二叉树只有两种情况,情况一:就是满二叉树,情况二:最后一层叶子节点没有满。

  • 对于情况一,可以直接用 2^树深度 - 1 来计算,注意这里根节点深度为1。

  • 对于情况二,分别递归左孩子,和右孩子,递归到某一深度一定会有左孩子或者右孩子为满二叉树,然后依然可以按照情况1来计算。

这里我们可以对左海孩子的深度进行比较:

  • 如果根节点的左子树深度等于右子树深度,则说明左子树为满二叉树

left == right

  • 如果根节点的左子树深度大于右子树深度,则说明右子树为满二叉树

如果知道子树是满二叉树,那么就可以轻松得到该子树的节点数目,为了加快幂的运算速度,可以使用移位操作符

(1<<depth) - 1; // depth为子树的深度;

完整代码如下:

/**
 * 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:
    int countDepth(TreeNode* node) {
        int depth = 0;
        while (node) {
            node = node->left;
            depth++;
        }
        return depth;
    }

    int countNodes(TreeNode* root) {
        if (root == NULL) return 0;
        int leftDepth = countDepth(root->left);
        int rightDepth = countDepth(root->right);
        if (leftDepth == rightDepth) return (1 << leftDepth) + countNodes(root->right);
        else return (1 << rightDepth) + countNodes(root->left);
    }
};
posted @ 2022-12-06 23:45  脱线森林`  阅读(1167)  评论(0编辑  收藏  举报