LeetCode 第111题:二叉树的最小深度

LeetCode 第111题:二叉树的最小深度

题目描述

给定一个二叉树,找出其最小深度。

最小深度是从根节点到最近叶子节点的最短路径上的节点数量。

说明: 叶子节点是指没有子节点的节点。

难度

简单

题目链接

点击在LeetCode中查看题目

示例

示例 1:

csharp 复制代码
输入:root = [3,9,20,null,null,15,7]
输出:2

示例 2:

csharp 复制代码
输入:root = [2,null,3,null,4,null,5,null,6]
输出:5

提示

  • 树中节点数的范围在 [0, 10^5]
  • -1000 <= Node.val <= 1000

解题思路

方法一:深度优先搜索(DFS)

最直观的方法是使用递归进行深度优先搜索。对于每个节点,我们需要:

关键点:

  • 如果节点为空,返回0
  • 如果节点是叶子节点(左右子节点都为空),返回1
  • 如果节点的左子树为空,返回右子树的最小深度+1
  • 如果节点的右子树为空,返回左子树的最小深度+1
  • 如果节点的左右子树都不为空,返回左右子树最小深度的较小值+1

具体步骤:

  1. 如果根节点为空,返回0
  2. 如果根节点的左右子节点都为空,返回1
  3. 如果根节点的左子节点为空,返回右子树的最小深度+1
  4. 如果根节点的右子节点为空,返回左子树的最小深度+1
  5. 如果根节点的左右子节点都不为空,返回左右子树最小深度的较小值+1

时间复杂度:O(n),其中n是树中节点的数量,最坏情况下需要遍历所有节点 空间复杂度:O(h),其中h是树的高度,递归调用栈的深度

方法二:广度优先搜索(BFS)

使用广度优先搜索可以更高效地找到最小深度,因为BFS会按层遍历,一旦找到第一个叶子节点,就可以立即返回当前深度。

关键点:

  • 使用队列进行层序遍历
  • 记录当前遍历的层数
  • 一旦找到叶子节点,立即返回当前层数

具体步骤:

  1. 如果根节点为空,返回0
  2. 初始化队列,将根节点入队,深度设为1
  3. 当队列不为空时,执行以下操作: a. 获取当前层的节点数量 b. 遍历当前层的所有节点 c. 对于每个节点,检查是否为叶子节点,如果是,返回当前深度 d. 如果不是叶子节点,将其非空子节点加入队列
  4. 深度加1,继续下一层的遍历

时间复杂度:O(n),最坏情况下需要遍历所有节点 空间复杂度:O(n),队列中最多存储n个节点

图解思路

方法一:DFS递归过程分析表

节点 左子树 右子树 最小深度 说明
3 9 20 2 左子树深度为1,右子树深度为2,取较小值1+1=2
9 null null 1 叶子节点,深度为1
20 15 7 2 左右子树深度均为1,取较小值1+1=2
15 null null 1 叶子节点,深度为1
7 null null 1 叶子节点,深度为1

方法二:BFS层序遍历过程表

层数 队列内容 是否找到叶子节点 说明
1 [3] 根节点不是叶子节点
2 [9, 20] 节点9是叶子节点,返回当前层数2

代码实现

C# 实现

csharp 复制代码
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     public int val;
 *     public TreeNode left;
 *     public TreeNode right;
 *     public TreeNode(int val=0, TreeNode left=null, TreeNode right=null) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
public class Solution {
    // 方法一:深度优先搜索(DFS)
    public int MinDepth(TreeNode root) {
        // 如果根节点为空,返回0
        if (root == null) {
            return 0;
        }
    
        // 如果是叶子节点,返回1
        if (root.left == null && root.right == null) {
            return 1;
        }
    
        // 如果左子树为空,返回右子树的最小深度+1
        if (root.left == null) {
            return MinDepth(root.right) + 1;
        }
    
        // 如果右子树为空,返回左子树的最小深度+1
        if (root.right == null) {
            return MinDepth(root.left) + 1;
        }
    
        // 如果左右子树都不为空,返回左右子树最小深度的较小值+1
        return Math.Min(MinDepth(root.left), MinDepth(root.right)) + 1;
    }
  
    // 方法二:广度优先搜索(BFS)
    public int MinDepthBFS(TreeNode root) {
        // 如果根节点为空,返回0
        if (root == null) {
            return 0;
        }
    
        // 初始化队列和深度
        Queue<TreeNode> queue = new Queue<TreeNode>();
        queue.Enqueue(root);
        int depth = 1;
    
        // BFS层序遍历
        while (queue.Count > 0) {
            int levelSize = queue.Count;
        
            // 遍历当前层的所有节点
            for (int i = 0; i < levelSize; i++) {
                TreeNode node = queue.Dequeue();
            
                // 如果找到叶子节点,返回当前深度
                if (node.left == null && node.right == null) {
                    return depth;
                }
            
                // 将非空子节点加入队列
                if (node.left != null) {
                    queue.Enqueue(node.left);
                }
                if (node.right != null) {
                    queue.Enqueue(node.right);
                }
            }
        
            // 深度加1
            depth++;
        }
    
        return depth;
    }
}

Python 实现

python 复制代码
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    # 方法一:深度优先搜索(DFS)
    def minDepth(self, root: Optional[TreeNode]) -> int:
        # 如果根节点为空,返回0
        if not root:
            return 0
    
        # 如果是叶子节点,返回1
        if not root.left and not root.right:
            return 1
    
        # 如果左子树为空,返回右子树的最小深度+1
        if not root.left:
            return self.minDepth(root.right) + 1
    
        # 如果右子树为空,返回左子树的最小深度+1
        if not root.right:
            return self.minDepth(root.left) + 1
    
        # 如果左右子树都不为空,返回左右子树最小深度的较小值+1
        return min(self.minDepth(root.left), self.minDepth(root.right)) + 1
  
    # 方法二:广度优先搜索(BFS)
    def minDepthBFS(self, root: Optional[TreeNode]) -> int:
        # 如果根节点为空,返回0
        if not root:
            return 0
    
        # 初始化队列和深度
        queue = collections.deque([(root, 1)])
    
        # BFS层序遍历
        while queue:
            node, depth = queue.popleft()
        
            # 如果找到叶子节点,返回当前深度
            if not node.left and not node.right:
                return depth
        
            # 将非空子节点加入队列
            if node.left:
                queue.append((node.left, depth + 1))
            if node.right:
                queue.append((node.right, depth + 1))
    
        return 0

C++ 实现

cpp 复制代码
/**
 * 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:
    // 方法一:深度优先搜索(DFS)
    int minDepth(TreeNode* root) {
        // 如果根节点为空,返回0
        if (root == nullptr) {
            return 0;
        }
    
        // 如果是叶子节点,返回1
        if (root->left == nullptr && root->right == nullptr) {
            return 1;
        }
    
        // 如果左子树为空,返回右子树的最小深度+1
        if (root->left == nullptr) {
            return minDepth(root->right) + 1;
        }
    
        // 如果右子树为空,返回左子树的最小深度+1
        if (root->right == nullptr) {
            return minDepth(root->left) + 1;
        }
    
        // 如果左右子树都不为空,返回左右子树最小深度的较小值+1
        return min(minDepth(root->left), minDepth(root->right)) + 1;
    }
  
    // 方法二:广度优先搜索(BFS)
    int minDepthBFS(TreeNode* root) {
        // 如果根节点为空,返回0
        if (root == nullptr) {
            return 0;
        }
    
        // 初始化队列和深度
        queue<pair<TreeNode*, int>> q;
        q.push({root, 1});
    
        // BFS层序遍历
        while (!q.empty()) {
            TreeNode* node = q.front().first;
            int depth = q.front().second;
            q.pop();
        
            // 如果找到叶子节点,返回当前深度
            if (node->left == nullptr && node->right == nullptr) {
                return depth;
            }
        
            // 将非空子节点加入队列
            if (node->left != nullptr) {
                q.push({node->left, depth + 1});
            }
            if (node->right != nullptr) {
                q.push({node->right, depth + 1});
            }
        }
    
        return 0;
    }
};

执行结果

C# 实现

  • 执行用时:92 ms
  • 内存消耗:41.2 MB

Python 实现

  • 执行用时:48 ms
  • 内存消耗:17.5 MB

C++ 实现

  • 执行用时:232 ms
  • 内存消耗:144.2 MB

性能对比

语言 执行用时 内存消耗 特点
C# 92 ms 41.2 MB 递归实现简洁,性能适中
Python 48 ms 17.5 MB 代码最简洁,在此题中性能最佳
C++ 232 ms 144.2 MB 内存占用较大,但在大规模数据上可能更高效

代码亮点

  1. 🎯 针对不同子树情况的特殊处理,避免了不必要的递归
  2. 💡 BFS方法一旦找到叶子节点立即返回,避免了不必要的遍历
  3. 🔍 正确处理了叶子节点的定义(没有子节点的节点)
  4. 🎨 代码结构清晰,逻辑分支处理完整

常见错误分析

  1. 🚫 忽略了叶子节点的定义,错误地认为任何节点都可以计算深度
  2. 🚫 没有正确处理单侧子树为空的情况,导致计算错误
  3. 🚫 在DFS中没有考虑到最小深度是到叶子节点的路径,而不是任意节点
  4. 🚫 在BFS实现中忘记检查节点是否为叶子节点,导致提前返回错误结果

解法对比

解法 时间复杂度 空间复杂度 优点 缺点
DFS O(n) O(h) 实现简单,递归逻辑清晰 最坏情况下可能遍历整棵树
BFS O(n) O(n) 一旦找到叶子节点立即返回,通常更高效 需要额外的队列空间

相关题目

相关推荐
珹洺40 分钟前
JSP技术入门指南【一】利用IDEA从零开始搭建你的第一个JSP系统
java·开发语言·前端·html·intellij-idea·jsp
tkevinjd1 小时前
并查集(力扣1971)
算法·leetcode·图论·并查集
Dovis(誓平步青云)1 小时前
【数据结构】励志大厂版·初阶(复习+刷题):线性表(顺序表)
c语言·数据结构·经验分享·笔记·学习·算法·学习方法
是Dream呀1 小时前
深度学习算法:从基础到实践
人工智能·深度学习·算法
Y1nhl1 小时前
搜广推校招面经七十五
人工智能·深度学习·算法·机器学习·支持向量机·推荐算法·搜索算法
Brookty2 小时前
【算法】归并排序
数据结构·算法·排序算法
2401_878454534 小时前
Themeleaf复用功能
前端·学习
星星火柴9364 小时前
数据结构:哈希表 | C++中的set与map
数据结构·c++·笔记·算法·链表·哈希算法·散列表
葡萄城技术团队5 小时前
基于前端技术的QR码API开发实战:从原理到部署
前端