104. 二叉树的最大深度
题目:
给定一个二叉树,找出其最大深度。
二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。
说明: 叶子节点是指没有子节点的节点。
解法1:递归
class Solution {
public:
int maxDepth(TreeNode* root) {
if (NULL == root)
return 0;
int leftDep = maxDepth(root->left) + 1;
int rightDep = maxDepth(root->right) + 1;
return leftDep > rightDep ? leftDep : rightDep;
}
};
在递归中,如果不想用到临时变量,可以选择用max()方法。具体程序可参考如下:
class Solution {
public:
int maxDepth(TreeNode* root) {
if(root == NULL) {
return 0;
}
return max(maxDepth(root->left), maxDepth(root->right)) + 1;
}
};
有时候调用max()方法,程序无法识别,就会想到宏,具体程序可参考如下:
#define MAX(x,y) ((x)>(y)?(x):(y)) //莫忘最外层括号
class Solution {
public:
int maxDepth(TreeNode* root) {
if (NULL == root)
return 0;
return MAX(maxDepth(root->left), maxDepth(root->right)) + 1;
}
};
但是,这种实现会超出时间限制。为什么呢?
不由得想说明是宏?是在预编译的时候进行文本替换,那么在MAX的地方,运行时会调用maxDepth()三次:((x)>(y)?(x):(y))。所以当树比较深的时候会超时。因此,宏不要用在递归函数上。
解法2:用从上到下打印二叉树的思想,深度即层数
class Solution {
public:
int maxDepth(TreeNode* root) {
if(nullptr == root)
return 0;
queue<TreeNode*> que;
que.push(root);
int depth = 0;
while(!que.empty()){
depth++;
int len =que.size();
while (len--) {
TreeNode* node=que.front();
que.pop();
if(node->left!=nullptr)
que.push(node->left);
if(node->right!=nullptr)
que.push(node->right);
}
}
return depth;
}
};
解法3:用一个全局变量记录层数,每层判断
class Solution {
public:
void cntLevel(TreeNode* root, int curLevel, int& depth) {
if (NULL == root)
return;
if (curLevel > depth)
depth = curLevel;
cntLevel(root->left, curLevel + 1, depth);
cntLevel(root->right, curLevel + 1, depth);
}
int maxDepth(TreeNode* root) {
int depth = 0;
cntLevel(root, 1, depth);
return depth;
}
};
这种方法,没有递归调用,也不用操作具体的节点,效率较高。
110. 平衡二叉树
题目:
给定一个二叉树,判断它是否是高度平衡的二叉树。
本题中,一棵高度平衡二叉树定义为:
一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过1。
解法1:计算数的深度,由上至下
class Solution {
private:
int treeDepth(TreeNode* root) {
if (NULL == root)
return 0;
return max(treeDepth(root->left), treeDepth(root->right)) + 1;
}
public:
bool isBalanced(TreeNode* root) {
if (NULL == root)
return true;
return abs(treeDepth(root->left) - treeDepth(root->right)) <= 1
&& isBalanced(root->left)
&& isBalanced(root->right);
}
};
解法2:由下至上,子树不平衡即不平衡
class Solution {
private:
bool isBalance(TreeNode* root, int& deep) {
if (NULL == root) {
deep = 0;
return true;
}
int leftLen, rightLen;
if (isBalance(root->left, leftLen)
&& isBalance(root->right, rightLen)
&& abs(leftLen - rightLen) <= 1) {
deep = max(leftLen, rightLen) + 1;
return true;
}
return false;
}
public:
bool isBalanced(TreeNode* root) {
if (NULL == root)
return true;
int deep = 0;
return isBalance(root, deep);
}
};
这种思路是在计算长度的时候,及时判断是否为平衡。此思路还有另一种实现,具体如下程序:
class Solution {
private:
int depth(TreeNode* root, bool& flag) {
if (NULL == root) {
flag = true;
return 0;
}
bool left, right;
int leftLen = depth(root->left, left);
int rightLen = depth(root->right, right);
if (left && right && abs(leftLen - rightLen) <= 1) {
flag = true;
return max(leftLen, rightLen) + 1;
}
flag = false;
return -1; //无效,无须计算
}
public:
bool isBalanced(TreeNode* root) {
if (NULL == root)
return true;
bool flag;
depth(root, flag);
return flag;
}
};
111. 二叉树的最小深度
题目:
给定一个二叉树,找出其最小深度。
最小深度是从根节点到最近叶子节点的最短路径上的节点数量。
说明: 叶子节点是指没有子节点的节点。
题目要点:
最小深度定义为到最近叶子节点的深度,当左右子树都为空,最小深度才为1。
解法1:分类讨论子节点情况
class Solution {
public:
int minDepth(TreeNode* root) {
if (NULL == root)
return 0;
int left = minDepth(root->left);
int right = minDepth(root->right);
if (0 == left && 0 == right) //1为根节点所在的深度
return 1;
if (0 == left || 0 == right)
return 0 == left ? right + 1 : left + 1;
return min(left, right) + 1;
}
};
这种解法根据返回情况写的很详细直白,理解后返回判断可以进一步简写如下:
class Solution {
public:
int minDepth(TreeNode* root) {
if (NULL == root)
return 0;
int left = minDepth(root->left);
int right = minDepth(root->right);
if (0 == left || 0 == right)
return max(left, right) + 1; //1为根节点所在的深度
return min(left, right) + 1;
}
};
甚至可以直接简写为一个三元式,具体程序如下:
class Solution {
public:
int minDepth(TreeNode* root) {
if (NULL == root)
return 0;
int left = minDepth(root->left);
int right = minDepth(root->right);
return (left && right) ? 1 + min(left, right) : 1 + left + right;
}
};
其中(left && right)不成立时,说明左右子节点至少有一个为空,即left和right至少有一个为0, 1+left+right数值上等于要求的数,没有别的特殊意义。
有很多同学第一次写,很容易写成如下程序(本题的错误解法,通不过的测试例如[1,2]),这就是没有好好理解最小深度的定义。
class Solution {
public:
int minDepth(TreeNode* root) {
if (NULL == root)
return 0;
return min(minDepth(root->left), minDepth(root->right)) + 1;
}
};
解法2:用从上至下打印二叉树的队列思路,遇到叶子节点短路处理
class Solution {
public:
int minDepth(TreeNode* root) {
if(NULL == root)
return 0;
queue<TreeNode*> que;
que.push(root);
int depth = 0;
while(!que.empty()){
int len = que.size();
while (len--) {
TreeNode* node = que.front();
que.pop();
if(NULL == node->left && NULL == node->right)
return depth + 1;
if(node->left)
que.push(node->left);
if(node->right)
que.push(node->right);
}
depth++;
}
return depth;
}
};
这种思路,处理到第一个叶子节点就结束了,效率较好。