111. 二叉树的最小深度
求最小深度/根节点到最近叶子节点的最短路径上的节点数量;
递归解法
递归解1(错解)
尝试考虑:
在求解的过程中下落到某个树(t)时
-
如果(t)为空, 那么它的最小深度为0;
-
如果(t)的左子树和右子树都非空, 那么它的最小深度等于(1 + min(h_l, h_r));
-
如果(t)的左子树为空或右子树为空, 那么它的最小深度等于1;
可以写出如下代码
class Solution {
public:
int minDepth(TreeNode* root) {
if(root==nullptr) return 0;
if(root->left!=nullptr && root->right!=nullptr) return 1 + min(minDepth(root->left), minDepth(root->right));
return 1;
}
};
这显然是错误的, 例如:
输入:
[1,2]
输出
1
预期结果
2
PS: 实际上上面的三条规则是冗余的, 可以化简为:
-
如果(t)为空, 那么它的最小深度为0;
-
否则它的最小深度等于(1 + min(h_l, h_r));
递归解2
可以让被抛给递归函数的t确保为非空;
- 如果(t)的左右子树都非空, 则(minDepth = 1 + min(h_l, h_r));
- 再如果(t)的左右子树都为空, 则(minDepth = 1);
- 最后对于左右子树一个为空, (minDepth = 1 + minDepth_{非空子树});
class Solution {
public:
int helper(TreeNode* t) {
if(t->left!=nullptr && t->right!=nullptr) return 1 + min(minDepth(t->left), minDepth(t->right));
if(t->left==nullptr && t->right==nullptr) return 1;
return 1 + minDepth((t->left!=nullptr) ? t->left : t->right);
}
int minDepth(TreeNode* root) {
if(root==nullptr) return 0;
return helper(root);
}
};
执行用时 :20 ms, 在所有 C++ 提交中击败了35.52%的用户
内存消耗 :21.6 MB, 在所有 C++ 提交中击败了5.10%的用户
递归解3
官方题解
class Solution {
public:
int minDepth(TreeNode* root) {
if(root==nullptr) return 0;
if(root->left==nullptr && root->right==nullptr) return 1;
int minD = INT_MAX;
if(root->left!=nullptr) minD = min(minD, minDepth(root->left));
if(root->right!=nullptr) minD = min(minD, minDepth(root->right));
return 1+minD;
}
};
执行用时 :20 ms, 在所有 C++ 提交中击败了35.52%的用户
内存消耗 :22.1 MB, 在所有 C++ 提交中击败了5.10%的用户
注:
- 以上题解都注意区分了根节点为空的情况;
迭代解
求一棵树的最大深度过程中, 我们记得层序遍历的时候, 可以获得当前遍历的深度, 所以直接可以得出最大深度;
而在层序遍历时, 也可以知道当前这个节点是不是叶子节点;
class Solution {
public:
int minDepth(TreeNode* root) {
if(root==nullptr) return 0;
int minD = INT_MAX;
deque<TreeNode*> q;
q.push_back(root);
int curDepth = 1;
while(!q.empty()) {
int n = q.size();
for(int i=0; i<n; ++i) {
TreeNode* t = q.front();
q.pop_front();
if(t->left==nullptr && t->right==nullptr)
minD = min(minD, curDepth);
if(t->left!=nullptr) q.push_back(t->left);
if(t->right!=nullptr) q.push_back(t->right);
}
++curDepth;
}
return minD;
}
};
效率都差不多
执行用时 :20 ms, 在所有 C++ 提交中击败了35.52%的用户
内存消耗 :21.3 MB, 在所有 C++ 提交中击败了5.10%的用户
上面的方法还有一处愚蠢:
- BFS层序遍历过程中深度是单调增的, 所以找到的第一个叶子节点深度就是最终要求的minDepth;
class Solution {
public:
int minDepth(TreeNode* root) {
if(root==nullptr) return 0;
int minD = INT_MAX;
deque<TreeNode*> q;
q.push_back(root);
int curDepth = 1;
while(!q.empty()) {
int n = q.size();
for(int i=0; i<n; ++i) {
TreeNode* t = q.front();
q.pop_front();
if(t->left==nullptr && t->right==nullptr) {
minD = min(minD, curDepth);
break; /// #找到第一个叶子即完成
}
if(t->left!=nullptr) q.push_back(t->left);
if(t->right!=nullptr) q.push_back(t->right);
}
++curDepth;
}
return minD;
}
};
快了不少
执行用时 :12 ms, 在所有 C++ 提交中击败了85.32%的用户
内存消耗 :21.4 MB, 在所有 C++ 提交中击败了5.10%的用户