代码随想录算法训练营第20天|LeetCode104.二叉树的最大深度、LeetCode111.二叉树的最小深度、LeetCode222.完全二叉树的节点个数
1.LeetCode104.二叉树的最大深度
这道题在学习层序遍历的时候做过了(是怒刷十道层序遍历题目中的其中之一),当时用的是迭代法,今天用递归法做一下。
迭代法
class Solution {
public:
int maxDepth(TreeNode* root) {
//法1 层序遍历迭代法
int res=0;
queue<TreeNode*> que;
if(root == NULL)
return res;
que.push(root);
while(!que.empty()){
//这一层有几个结点
int size = que.size();
for(int i=0;i<size;i++){//注意这里用前面得到的size而不是que.size(),que.size()实时变化
TreeNode* front = que.front();
que.pop();
if(front->left)
que.push(front->left);
if(front->right)
que.push(front->right);
}
res++;
}
return res;
}
};
递归法
可以使用前序(中左右),也可以使用后序遍历(左右中),使用前序求的就是深度,使用后序求的是高度。
- 二叉树节点的深度:指从根节点到该节点的最长简单路径边的条数或者节点数(取决于深度从0开始还是从1开始)
- 二叉树节点的高度:指从该节点到叶子节点的最长简单路径边的条数或者节点数(取决于高度从0开始还是从1开始)
而根节点的高度就是二叉树的最大深度 。
后续遍历(左右中)计算树的高度
- 确定递归函数的参数和返回值:参数就是传入树的根节点,返回就返回这棵树的深度,所以返回值为int类型。
- 确定终止条件:如果为空节点的话,就返回0,表示高度为0。
- 确定单层递归的逻辑:先求它的左子树的深度,再求右子树的深度,最后取左右深度最大的数值 再+1 (加1是因为算上当前中间节点)就是目前节点为根节点的树的深度。
代码
class Solution {
public:
int maxDepth(TreeNode* root) {
//法2 后续遍历递归法
if(root == NULL)
return 0;
return max(maxDepth(root->left), maxDepth(root->right) )+1;
}
};
前序遍历
充分表现出求深度回溯的过程 。
这个代码其实感觉相较于后序遍历和迭代的方法会更难理解。
class solution {
public:
int result;
void getdepth(TreeNode* node, int depth) {
result = depth > result ? depth : result; // 中
if (node->left == NULL && node->right == NULL) return ;
if (node->left) { // 左
depth++; // 深度+1
getdepth(node->left, depth);
depth--; // 回溯,深度-1
}
if (node->right) { // 右
depth++; // 深度+1
getdepth(node->right, depth);
depth--; // 回溯,深度-1
}
return ;
}
int maxDepth(TreeNode* root) {
result = 0;
if (root == NULL) return result;
getdepth(root, 1);
return result;
}
};
2.LeetCode111.二叉树的最小深度
之前在层序遍历的时候做过这道题。
迭代法
class Solution {
public:
int minDepth(TreeNode* root) {
int res=0;
queue<TreeNode*> que;
if(root == NULL)
return res;
que.push(root);
bool flag=false;
while(!que.empty()){
//这一层有几个结点
int size = que.size();
res++;
for(int i=0;i<size;i++){//注意这里用前面得到的size而不是que.size(),que.size()实时变化
TreeNode* front = que.front();
que.pop();
// cout<<(front->left==front->right==NULL)<<endl;
if(front->left == front->right){
cout<<"all empty"<<endl;
flag = true;
break;
}
if(front->left)
que.push(front->left);
if(front->right)
que.push(front->right);
}
if(flag)
break;
}
return res;
}
};
递归法
后序遍历
三部曲
- 确定递归函数的参数和返回值
参数为要传入的二叉树根节点,返回的是int类型的深度。
- 确定终止条件
终止条件也是遇到空节点返回0,表示当前节点的高度为0。
- 确定单层递归的逻辑
与求最大深度不同,容易犯错:
int leftDepth = getDepth(node->left);
int rightDepth = getDepth(node->right);
int result = 1 + min(leftDepth, rightDepth);
return result;
上面代码会导致“没有左孩子的分支为最小深度”
因此,如果左子树为空,右子树不为空,说明最小深度是 1 + 右子树的深度。反之,右子树为空,左子树不为空,最小深度是 1 + 左子树的深度。 最后如果左右子树都不为空,返回左右子树深度最小值 + 1 。
int leftDepth = getDepth(node->left); // 左
int rightDepth = getDepth(node->right); // 右
// 中
// 当一个左子树为空,右不为空,这时并不是最低点
if (node->left == NULL && node->right != NULL) {
return 1 + rightDepth;
}
// 当一个右子树为空,左不为空,这时并不是最低点
if (node->left != NULL && node->right == NULL) {
return 1 + leftDepth;
}
int result = 1 + min(leftDepth, rightDepth);
return result;
完整的精简的代码:
犯错:
- 最后都为空/不空不用再写if判断,否则会报没有返回值的错
- 都为空/不空忘记+1
class Solution {
public:
int minDepth(TreeNode* root) {
if (root == NULL) return 0;
// 有且仅有1个为空
if (root->left == NULL && root->right != NULL) {
return 1 + minDepth(root->right);
}
if (root->left != NULL && root->right == NULL) {
return 1 + minDepth(root->left);
}
//都不为空/都空
return 1 + min(minDepth(root->left), minDepth(root->right));
}
};
3、LeetCode222.完全二叉树的节点个数
普通二叉树
第一想法:
- 层序遍历然后数数
- 或者递归遍历,引用传递个数
但只考虑了普通二叉树,而没有利用完全二叉树的性质。
递归代码:
一遍过!
class Solution {
public:
void preorder(TreeNode* root, int &cnt){
if(root==NULL)
return;
else
cnt++;
preorder(root->left, cnt);
preorder(root->right, cnt);
}
int countNodes(TreeNode* root) {
int cnt=0;
preorder(root,cnt);
return cnt;
}
};
迭代法代码去看层序遍历的笔记。
完全二叉树
在完全二叉树中,如果递归向左遍历的深度等于递归向右遍历的深度,那说明就是满二叉树。
下面是满二叉树。
下面不是满二叉树
下面不是完全二叉树 !
思路:
如果左右子树不是满二叉树,则递归,知道找到满二叉树。叶子节点总是满二叉树。
实际上是后续遍历-见代码
代码:
**犯错:**leftDepth从0开始,是满二叉树时忘记+1,忘记加上根节点。
class Solution {
public:
int countNodes(TreeNode* root) {
//法2 利用完全二叉树的性质
if(root == NULL)
return 0;
TreeNode* left = root->left;
TreeNode* right = root->right;
int leftDepth = 0;
int rightDepth = 0;
// 分别向左、向右遍历
while(left){
leftDepth++;
left = left->left;
}
while(right){
rightDepth++;
right = right->right;
}
// 是满二叉树
if(leftDepth == rightDepth)
return (1<<leftDepth+1)-1;
// 不是满二叉树
return countNodes(root->left)+countNodes(root->right)+1;
}
};