104. 二叉树的最大深度--二叉树--初级算法

链接:104. 二叉树的最大深度 - 力扣(LeetCode)


题目

        给定一个二叉树 root ,返回其最大深度。二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。

示例 1:

输入:root = [3,9,20,null,null,15,7]
输出:3

思路

一、递归

        对左右子树进行递归,当到达叶节点返回1,空节点返回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:
    int maxDepth(TreeNode* root) {
        //空指针则返回0
        if(root==nullptr){
            return 0;
        }
        //叶节点,返回1
        if(root->left==nullptr&&root->right==nullptr){
            return 1;
        }
        //左右子树递归
        int maxleft=maxDepth(root->left);
        int maxright=maxDepth(root->right);
        //比较使最深的子树返回深度加一
        if(maxleft>=maxright){
            return maxleft+1;
        }
        else{
            return maxright+1;
        }
    }
};

简化写法:

class Solution {
public:
    int maxDepth(TreeNode* root) {
        return root==nullptr ? 0 : max(maxDepth(root->left),maxDepth(root->right))+1;
    }
};

二、广度优先搜索BFS

也叫层序遍历        

        利用队列实现,将每层节点入队,出队时依次将每个结点的左右非空节点入队,本层节点全部出队后进入下一层的遍历,所以层数加一,层数就是树的深度。待所有节点都遍历后返回深度。

代码实现:

/**
 * 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) {
        if(root==nullptr){
            return 0;
        }
        //定义一个队列
        queue<TreeNode*> q;
        //根节点入队
        q.push(root);
        //统计树的深度
        int count=0;
        while(!q.empty()){
            int n=q.size();//每一层的节点个数
            while(n--){
                //将每层节点的左右孩子入队
                TreeNode* cur=q.front();
                q.pop();
                if(cur->left){
                    q.push(cur->left);
                }
                if(cur->right){
                    q.push(cur->right);
                }
            }
            //层数加一,层数即为深度
            count++;
        }
        return count;
    }
};

结果:

三、深度优先搜索DFS

        深度优先搜索就是从根节点开始沿着一条路径往下遍历,直到遇到空节点不能继续遍历,然后返回到上一个节点从另一条路径继续向下遍历,直到所有节点都被访问为止。

        这里用栈实现对节点和所在层数的存储,于是用c++提供的模板类pair存储Treenode类型和int类型,使用时分别用first和second访问第一个和第二个参数,只要栈不为空就继续遍历,遍历时先存储栈顶,再出栈,每次比较当前层数和目前的最大深度,取最大值更新后,再访问左右子节点,记得将层数加一,全部遍历完返回最大深度即可。

代码实现:

/**
 * 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) {
        if(root==nullptr){
            return 0;
        }
        //定义栈,双数据类型分别存储树节点和所在层数
        stack<pair<TreeNode*,int>> st;
        //根节点入栈,层数为1
        st.push({root,1});
        int maxcount=0;
        while(!st.empty()){
            //由于pair有两个数据类型,所以用auto类型
            auto cur=st.top();
            st.pop();
            //取最大值,注意cur为pair模板类,调用second即为第二个参数int类型也就是层数
            maxcount=max(maxcount,cur.second);
            //左右遍历,入栈,cur.first即为节点类型
            if(cur.first->right){
                st.push({cur.first->right,cur.second+1});
            }
            if(cur.first->left){
                st.push({cur.first->left,cur.second+1});
            }
        }
        return maxcount;
    }
};

注意:

  pair是C++标准库中的一个模板类,用于存储两个不同类型的值,并将它们作为一个单元进行管理。

pair的定义如下:

template <class T1, class T2>
struct pair {
  T1 first;
  T2 second;
};

其中T1T2可以是任意类型。

pair的用法主要包括以下几个方面:

1、创建pair对象:

pair<int, double> p1(10, 3.14); // 使用值初始化
pair<int, double> p2 = make_pair(5, 2.5); // 使用make_pair函数创建

2、访问pair对象的成员:

int x = p1.first;   // 获取第一个值,即 10
double y = p1.second;  // 获取第二个值,即 3.14

3、修改pair对象的成员:

p1.first = 20;   // 修改第一个值为 20
p1.second = 6.28; // 修改第二个值为 6.28

4、比较pair对象的大小:

pair<int, double> p1(10, 3.14);
pair<int, double> p2(20, 6.28);

bool result = (p1 < p2); // 比较p1和p2的大小,结果为true

  auto是C++11中引入的关键字,用于自动推导变量的类型。使用auto可以让编译器根据初始化表达式的类型来推导变量的类型,从而简化代码并减少类型冗余。

下面是使用auto的一些优点和使用场景:

  1. 减少冗余:使用auto可以避免手动指定变量类型,减少代码中的类型冗余,提高代码的可读性。

  2. 简化复杂类型:当变量的类型很长或复杂时,使用auto可以避免手动写出完整的类型名称,减少代码的复杂性。

  3. 泛型编程:auto可以与模板一起使用,用于处理不同类型的对象,使代码更加灵活和通用。

  4. 函数返回类型推导:在函数定义中,可以使用auto来自动推导返回类型,特别适用于复杂的返回类型或涉及模板的情况。

  5. 迭代器和范围遍历:使用auto可以自动推导迭代器和范围遍历所需的类型,使代码更简洁、易读。

  6. Lambda表达式:在使用Lambda表达式时,使用auto可以方便地声明和推导Lambda函数的类型。

虽然auto有这些好处,但也需注意:

  1. 可读性和维护性:过度使用auto可能使代码难以理解,尤其是在没有清晰初始化表达式的情况下。适当使用auto可以提高代码的可读性,但需更好地命名和注释变量。

  2. 隐藏信息:类型推导可能隐藏变量的实际类型,使代码的含义难以理解和推断。在某些情况下,显式指定类型可能更好地表达代码的意图。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值