代码随想录算法训练营第十六天|Leetcode104 二叉树的最大深度 、Leetcode111 二叉树的最小深度、Leetcode222 完全二叉树的节点个数
● Leetcode104 二叉树的最大深度
题目链接:Leetcode104 二叉树的最大深度
视频讲解:代码随想录|二叉树的最大深度
题目描述:给定一个二叉树 root ,返回其最大深度。
二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。
示例 1:
输入:root = [3,9,20,null,null,15,7]
输出:3
示例 2:
输入:root = [1,null,2]
输出:2
● Prerequisite
二叉树节点的深度: 指从根节点到该节点的最长简单路径边的条数或者节点数(取决于深度从0开始还是从1开始);
二叉树节点的高度: 指从该节点到叶子节点的最长简单路径边的条数或者节点数(取决于高度从0开始还是从1开始。
深度和高度的讨论对象都是二叉树,高度
必然从从下向上定义,相反深度
则是从上向下定义,讨论数的高度和深度就像讨论树在地面上的高度和树根在地面下的深度一样。
基于对高度和深度的理解,我们需要知道常规对于高度和深度处理使用哪种遍历:
高度: 因为高度是自下而上,也就是从叶子节点开始向根节点靠近,需要将子结点高度信息返回给父结点,因此需要使用后序遍历
;
深度: 深度自上而下,也就是将根节点的高度需要返回给子结点,满足这个遍历顺序的自然就是前序遍历
。
● 解题思路
对于最大深度的解决,使用前序和后序遍历都可以,因为返回的都是根节点到叶子节点的最大距离。
后序遍历: 使用递归进行后序遍历,可以自定义getDepth()
函数分别获取左右子树的高度,而对于二叉树的最大高度则是取两者的最大值随后加上根结点的一层即可。
前序遍历: 使用前序遍历解决最大深度则是对回溯的考察,我们需要对比取当前返回结果和子树深度的最大值;
假如左结点存在,则深度加一,然后向左孩子递归,每结束一次左孩子的递归需要深度减一,才能对右孩子进行递归,最后返回最大值即可。
迭代法
迭代法使用层序遍历更加合适一些,因为最大的深度就是二叉树的层数,和层序遍历的方式极其吻合。
● 代码实现
后序递归
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
int getDepth(TreeNode* root)
{
if(!root) return 0;
int leftDepth = getDepth(root->left);
int rightDepth = getDepth(root->right);
return 1 + max(leftDepth, rightDepth);
}
int maxDepth(TreeNode* root) {
return getDepth(root);
}
};
前序递归
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
int result;
void getDepth(TreeNode* node, int depth)
{
//取最大结果
result = depth > result ? depth : result;
if(!node->left && !node->right) return;
//递归遍历左孩子
if(node->left)
{
depth++; //左孩子存在,深度加一
getDepth(node->left, depth);
depth--; //深度减一,返回到node
}
/*简化代码
if (node->left) { // 左
getdepth(node->left, depth + 1);
}
*/
//递归遍历右孩子
if(node->right)
{
depth++; //右孩子存在,深度加一
getDepth(node->right, depth);
depth--; //深度减一,返回到node
}
/*简化代码
if (node->right) { // 左
getdepth(node->right, depth + 1);
}
*/
return;
}
int maxDepth(TreeNode* root) {
result = 0;
if(!root) return result;
getDepth(root, 1);
return result;
}
};
层序迭代
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
int maxDepth(TreeNode* root) {
if(!root) return 0;
queue<TreeNode*> que;
if(root) 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) que.push(node->left);
if(node->right) que.push(node->right);
}
}
return depth;
}
};
● 相关题目:Leetcode559 n叉树的最大深度
题目链接:Leetcode559 n叉树的最大深度
题目描述:给定一个 N 叉树,找到其最大深度。
最大深度是指从根节点到最远叶子节点的最长路径上的节点总数。
N 叉树输入按层序遍历序列化表示,每组子节点由空值分隔(请参见示例)。
示例 1:
输入:root = [1,null,3,2,4,null,5,6]
输出:3
示例 2:
输入:root = [1,null,2,3,4,5,null,null,6,7,null,8,null,9,10,null,null,11,null,12,null,13,null,null,14]
输出:5
● 代码实现
递归
/*
// Definition for a Node.
class Node {
public:
int val;
vector<Node*> children;
Node() {}
Node(int _val) {
val = _val;
}
Node(int _val, vector<Node*> _children) {
val = _val;
children = _children;
}
};
*/
class Solution {
public:
int maxDepth(Node* root) {
if(!root) return 0;
int depth = 0;
for(int i = 0; i < root->children.size(); i++)
{
depth = max(depth, maxDepth(root->children[i]));
}
return depth + 1;
}
};
迭代
/*
// Definition for a Node.
class Node {
public:
int val;
vector<Node*> children;
Node() {}
Node(int _val) {
val = _val;
}
Node(int _val, vector<Node*> _children) {
val = _val;
children = _children;
}
};
*/
class Solution {
public:
int maxDepth(Node* root) {
queue<Node*> que;
if(root) que.push(root);
int depth = 0;
while(!que.empty())
{
int size = que.size();
depth++;
for(int i = 0; i < size; i++)
{
Node* node = que.front(); que.pop();
for(int j = 0; j < node->children.size(); j++)
{
que.push(node->children[j]);
}
}
}
return depth;
}
};
● Leetcode111 二叉树的最小深度
题目链接:Leetcode111 二叉树的最小深度
视频讲解:代码随想录|二叉树的最小深度
题目描述:给定一个二叉树,找出其最小深度。
最小深度是从根节点到最近叶子节点的最短路径上的节点数量。
说明:叶子节点是指没有子节点的节点。
示例 1:
输入:root = [3,9,20,null,null,15,7]
输出:2
示例 2:
输入:root = [2,null,3,null,4,null,5,null,6]
输出:5
● 解题思路
需要注意最小深度的定义:最小深度是从根节点到最近叶子节点的最短路径上的节点数量。
如图,我们将结点3
的空左孩子画出来会发现,3
不属于叶子结点,NULL
也不属于叶子节点,对于图中叶子结点仅15
和7
。
基于对最小深度的理解,我们不能像解决Leetcode104 二叉树的最大深度一样取左右子树深度的最大值,需要对结点的左右孩子进行判断,如果都为空才能计入结果。
因此就存在三种情况:
(1)左孩子为空,右孩子不为空:需要递归获取右子树最小深度 + 1;
(2)左孩子不为空,右孩子为空:需要递归获取左子树最小深度 + 1;
(3)以上两种情况都解决之后,才可以取左右子树的最小深度 + 1。
● 代码实现
后序递归
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
int getDepth(TreeNode* node)
{
int depth = 0;
if(!node) return depth;
int leftDepth = getDepth(node->left); // 左
int rightDepth = getDepth(node->right); // 右
//中
if(!node->left && node->right) return 1 + rightDepth;
if(node->left && !node->right) return 1 + leftDepth;
return 1 + min(rightDepth, leftDepth);
}
int minDepth(TreeNode* root) {
return getDepth(root);
}
};
精简代码之后就是:
class Solution {
public:
int minDepth(TreeNode* root) {
if (root == NULL) return 0;
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));
}
};
前序递归
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
int result;
void getDepth(TreeNode* node, int depth)
{
//终止条件
if(!node) return;
//中
if(!node->left && !node->right) result = min(depth, result);
//左
if(node->left) getDepth(node->left, depth + 1);
//右
if(node->right) getDepth(node->right, depth + 1);
return;
}
int minDepth(TreeNode* root) {
if(!root) return 0;
result = INT_MAX;
getDepth(root, 1);
return result;
}
};
迭代
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
int minDepth(TreeNode* root) {
if(!root) return 0;
int depth = 0;
queue<TreeNode*> que;
que.push(root);
while(!que.empty())
{
int size = que.size();
depth++;
for(int i = 0; i < size; i++)
{
TreeNode* node = que.front(); que.pop();
if(node->left) que.push(node->left);
if(node->right) que.push(node->right);
if(!node->left && !node->right) return depth;
}
}
return depth;
}
};
● Leetcode222 完全二叉树的节点个数
题目链接:[Leetcode222 完全二叉树的节点个数]
视频讲解:[代码随想录|完全二叉树的节点个数]
题目描述:
● 解题思路
普通二叉树
如果我们把它当作普通二叉树处理,通过递归的方式我们获取左子树的结点个数和右子树的结点个数之后相加后再加一即可得到结果。
完全二叉树
我们知道对于完全二叉树有两种:一种是特殊的完全二叉树-满二叉树,另一种就是在满二叉树的基础上,在最后一层从右向左依次缺少结点。
但不管对于哪种完全二叉树,都会有一部分是满二叉树,而对于满二叉树的结点可以通过
nodesNum = 2 ^ n - 1
进行计算,因此我们需要先进行满二叉树的判定,符合条件可以直接使用公式进行该部分结点计算。
但如何进行满二叉树的判定,因为它一定是完全二叉树,所以我们可以通过左右深度是否相等进行判断,该过程也能帮助我们获取树的深度。
对于剩余部分,我们递归到叶子结点时,其单个结点也是完全二叉树,因此放心大胆往下递归,最后将左右子树结点和根节点个数加和即可。
● 代码实现
普通二叉树
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
int getNodesNum(TreeNode* root)
{
if(!root) return 0;
int leftNum = getNodesNum(root->left);
int rightNum = getNodesNum(root->right);
return 1 + leftNum + rightNum;
}
int countNodes(TreeNode* root) {
return getNodesNum(root);
}
};
满二叉树
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
int countNodes(TreeNode* root) {
if(!root) return 0;
TreeNode *left = root->left, *right = root->right;
int leftDepth = 0, rightDepth = 0;
while(left)//求左子树深度
{
leftDepth++;
left = left->left;
}
while(right)//求右子树深度
{
rightDepth++;
right = right->right;
}
if(leftDepth == rightDepth) return (2 << leftDepth) - 1;
return countNodes(root->left) + countNodes(root->right) + 1;
}
};
迭代
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
int countNodes(TreeNode* root) {
if(!root) return 0;
queue<TreeNode*> que;
que.push(root);
int num = 0;
while(!que.empty())
{
int size = que.size();
num += size;
for(int i = 0; i < size; i++)
{
TreeNode* node = que.front(); que.pop();
if(node->left) que.push(node->left);
if(node->right) que.push(node->right);
}
}
return num;
}
};
或者在每次pop()
队头元素之后做num++
也可以达到num += size
的效果。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
int countNodes(TreeNode* root) {
if(!root) return 0;
queue<TreeNode*> que;
que.push(root);
int num = 0;
while(!que.empty())
{
int size = que.size();
for(int i = 0; i < size; i++)
{
TreeNode* node = que.front(); que.pop();
num++;
if(node->left) que.push(node->left);
if(node->right) que.push(node->right);
}
}
return num;
}
};