- 二叉树的深度
这是剑指offer上的原题。用递归的方式很快写出如下代码,但是,速度很慢。
class Solution {
public:
int maxDepth(TreeNode* root) {
if(root == nullptr)
return 0;
if(!root->left && (!root->right))
return 1;
return 1 + max(maxDepth(root->left), maxDepth(root->right));
}
};
用队列来BFS,然后记录层数,仍然一样的慢。。。
class Solution {
public:
int maxDepth(TreeNode* root) {
if(!root)
return 0;
queue<TreeNode*> q;
int level=0;//这个地方容易错误的初始化为1. 实际上是dangyic
int curLevel = 1;
int nextLevel = 0;
q.push(root);
while(q.size())
{
if(q.front()->left)
{
q.push(q.front()->left);
nextLevel++;
}
if(q.front()->right)
{
q.push(q.front()->right);
nextLevel++;
}
q.pop();
curLevel--;
if(!curLevel)
{
curLevel=nextLevel;
nextLevel=0;
level++;
}
}
return level;
}
};
看了答案,其实第一种方法就是DFS。
2. 平衡树
在上一题的思路下,很容易想到递归遍历每个节点,求出每个节点的深度。判断是否平衡。
于是容易得到下面的代码:
class Solution {
public:
int height(TreeNode* root)
{
if(!root)
return 0;
int leftHeight = height(root->left);
int rightHeight = height(root->right);
return max(leftHeight, rightHeight)+1;
}
bool isBalanced(TreeNode* root) {
if(!root)
return true;
return abs(height(root->right)-height(root->left))<=1 && isBalanced(root->right) && isBalanced(root->left);
}
};
但是实际上,如果以某个节点为root的子树不是平衡树,那么我们不必知道它的深度,可以直接返回-1.
class Solution {
public:
int height(TreeNode* root)
{
if(!root)
return 0;
int leftHeight = height(root->left);
int rightHeight = height(root->right);
if(leftHeight==-1 || rightHeight==-1 || abs(leftHeight-rightHeight)>1)
return -1;
return max(leftHeight, rightHeight)+1; //别忘了+1,嘤嘤嘤
}
bool isBalanced(TreeNode* root) {
return height(root) >= 0;
}
};
- 二叉树的直径
遍历每个节点,每个节点的直径等于其左右子树的高度之和。维护一个最大直径指针,将每个节点的直径与直径的最大值作比较,并更新最大直径。
class Solution {
public:
int diameterOfBinaryTree(TreeNode* root) {
int res=0;
int* maxDiameter=&res;
//愚蠢的我最开始的写法竟然是:int* maxDiameter=0;
diameterOfBinaryTreeCore(root, maxDiameter);
return *maxDiameter;
}
void diameterOfBinaryTreeCore(TreeNode* root, int* maxDiameter)
{
if(!root)
return;
int leftHeight = height(root->left);
int rightHeight = height(root->right);
(*maxDiameter) = max(leftHeight + rightHeight, *maxDiameter);
diameterOfBinaryTreeCore(root->left, maxDiameter);
diameterOfBinaryTreeCore(root->right, maxDiameter);
}
int height(TreeNode* root)
{
if(!root)
return 0;
return max(height(root->left), height(root->right))+1;
}
};
上面这种思路用了两个递归来实现,两个递归实际上可以合并为一个递归
class Solution {
public:
int diameterOfBinaryTree(TreeNode* root) {
int res=0;
int* maxDiameter=&res;
height(root, maxDiameter);
return *maxDiameter;
}
int height(TreeNode* root, int* maxDiameter)
{
if(!root)
return 0;
int leftHeight = height(root->left,maxDiameter);
int rightHeight = height(root->right, maxDiameter);
(*maxDiameter) = max(leftHeight + rightHeight, *maxDiameter);
//后序遍历,每个节点只访问一遍,所以,时间复杂度是O(n)
return max(leftHeight, rightHeight) + 1;
}
};
进一步优化,可以不单独维护一个maxHeight指针,直接定义为类的成员变量不就行了。
4. 翻转树
原题,略。
5. 并归两棵树
嘿嘿,应该只用了5min不到。
果然就是,写递归之前,首先想清楚递归的传递条件是什么。
以本题为例,两棵树的并归,等价于根节点求和,左子树与左子树并归、右子树与右子树并归。
class Solution {
public:
TreeNode* mergeTrees(TreeNode* root1, TreeNode* root2) {
if(!root1)
return root2;
if(!root2)
return root1;
root1->val += root2->val;
root1->left = mergeTrees(root1->left, root2->left);
root1->right = mergeTrees(root1->right, root2->right);
return root1;
}
};