在解决二叉树相关问题时,最小深度是一个常见但容易出错的概念。与最大深度不同,最小深度需要考虑节点是否真正构成完整路径。让我们先明确最小深度的定义:从根节点到最近叶子节点的最短路径上的节点数量。这里的关键词是"叶子节点"——即没有子节点的节点。
初学者常犯的错误是简单套用最大深度的递归公式,直接返回左右子树最小深度的较小值加1。这种写法在遇到单边子树时会出错,比如当左子树为空时,实际上最小深度应该由右子树决定,而不是返回1(错误代码会把这种情况当作深度1处理)。
广度优先搜索(BFS)是解决最小深度问题的自然选择,因为它按层遍历节点,第一个遇到的叶子节点必然对应最小深度。这种方法的时间复杂度为O(n),空间复杂度在最坏情况下也是O(n)。
cpp复制class Solution {
public:
int minDepth(TreeNode* root) {
queue<TreeNode*> que;
if(root==nullptr) return 0;
que.push(root);
int depth = 0;
while(!que.empty()){
int size = que.size();
depth++;
for(int i=0; i<size; i++){
TreeNode* node = que.front();
que.pop();
if(!node->left && !node->right){
return depth;
}
if(node->left) que.push(node->left);
if(node->right) que.push(node->right);
}
}
return depth;
}
};
提示:在实际面试中,建议先口头说明BFS适合解决此问题的原因——它天然按层搜索,能最早找到最近的叶子节点。
递归解法需要考虑五种基本情况:
cpp复制class Solution {
public:
int minDepth(TreeNode* root) {
if(root==nullptr) return 0;
// 叶子节点
if(!root->left && !root->right) return 1;
// 只有右子树
if(!root->left) return minDepth(root->right)+1;
// 只有左子树
if(!root->right) return minDepth(root->left)+1;
// 完整子树
return min(minDepth(root->left), minDepth(root->right))+1;
}
};
常见的错误递归写法是:
cpp复制// 错误写法!
int minDepth(TreeNode* root) {
if(root==nullptr) return 0;
return min(minDepth(root->left), minDepth(root->right))+1;
}
这种写法的问题在于它无法正确处理单边子树的情况。例如:
code复制 1
\
2
\
3
按照错误写法会返回1,而实际最小深度是3。因为节点1虽然有右子树,但错误写法把它当作叶子节点处理了。
更简洁的递归实现方式:
cpp复制class Solution {
public:
int minDepth(TreeNode* root) {
if(!root) return 0;
int left = minDepth(root->left);
int right = minDepth(root->right);
// 处理单边为空的情况
if(!root->left || !root->right)
return max(left, right) + 1;
return min(left, right) + 1;
}
};
这种写法利用max处理单边子树的情况,逻辑更加紧凑。当一边子树为空时,最小深度必然在另一侧子树中,因此取较大值。
| 方法 | 平均时间复杂度 | 最坏时间复杂度 | 空间复杂度 |
|---|---|---|---|
| BFS | O(n) | O(n) | O(n) |
| 递归 | O(n) | O(n) | O(h) |
BFS更适合:
递归更适合:
注意:对于极度不平衡的树(如链表状的树),递归解法可能导致栈溢出,而BFS则没有这个问题。
可视化小树:手工绘制简单测试用例,如:
code复制 1
/ \
2 3
\
4
最小深度应为2
打印调试:在递归中打印当前节点值和深度:
cpp复制void helper(TreeNode* node, int depth) {
cout << "Node: " << (node?node->val:0)
<< " Depth: " << depth << endl;
// ...
}
边界测试:
在实际工程实践中,BFS通常是更稳妥的选择,特别是当树结构未知时。递归解法虽然代码简洁,但需要注意栈深度限制。我在实际项目中发现,对于系统目录树遍历这类问题,基于队列的非递归实现往往更可靠。