二叉树part03
104.二叉树的最大深度
题目
给定一个二叉树 root ,返回其最大深度。
二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。
思路
这道题有两种解法,先说递归解法。
递归有两种思路,一种是求树的深度(前序遍历),一种是求树的高度(后序遍历)。
递归解法1(求深度)
先说求树的深度,那么我们需要定义一个求树的深度的函数,因为是递归,所以按照递归三部曲(函数参数及返回值、递归终止条件、单层递归的逻辑):
函数参数及返回值:因为要得到树的深度,所以函数参数肯定包含一个TreeNode节点指针,还有一个int类型的参数depth作为当前节点的深度,好像返回值没什么好返回的;
递归终止条件:访问到空节点时就开始返回;
单层递归的逻辑:首先,进入一个节点,该节点的深度也传进来了,肯定要和当前最大深度(我们作为一个全局变量把最大深度存起来)比较,取其中较大值作为当前最大深度;然后,开始进入该节点的左孩子节点,右孩子节点;
递归代码1(求深度)
class Solution {
int maxdep=0;
public:
void getDepth(TreeNode* node, int depth){
maxdep=(depth>maxdep)?depth:maxdep;
if(node->left){
getDepth(node->left, depth+1);
}
if(node->right){
getDepth(node->right, depth+1);
}
}
int maxDepth(TreeNode* root) {
if(root==nullptr) return 0;
getDepth(root, 1);
return maxdep;
}
};
递归解法2(求高度)
求高度用后序遍历,还是按递归三部曲来分析:
函数参数及返回值:首先,和求深度时一样,肯定要传入一个TreeNode节点;与求深度不同的一点是,求深度时我们还需要传入一个depth,因为求深度使用的是前序遍历,先遍历当前节点,得到当前节点的深度,此时并不能返回,还需再遍历当前节点的左右孩子节点,而遍历左右孩子节点时是需要有父节点的深度的,无法用返回值传,只能用参数传了;而求高度时不需要额外传入height参数,因为求高度使用的是后序遍历,先遍历左右孩子节点得到左右孩子节点的高度的返回值,将返回值传入本节点得到本节点的高度,然后当前函数就返回了,所以直接用返回值就可以传height参数。
递归终止条件:访问到空节点时就返回;
单层递归的逻辑:访问到空节点时,肯定返回0,表示空节点的高度为0;先递归访问得到当前节点的左、右孩子节点的高度,取两个高度的最大值+1作为当前节点的高度,并返回。
递归代码2(求高度)
int getHeight(TreeNode* node){
if(node==nullptr) return 0;
int leftHeight=getHeight(node->left);
int rightHeight=getHeight(node->right);
return 1+max(leftHeight, rightHeight);
}
int maxDepth(TreeNode* root) {
return getHeight(root);
}
迭代解法
迭代法求最大高度,肯定是用层序遍历了,for循环每访问一层就depth++就可以了,代码如下:
迭代代码(层序遍历)
int maxDepth(TreeNode* root) {
if(root==nullptr) return 0;
int depth=0;
queue<TreeNode*> que;
que.push(root);
while(!que.empty()){
int size=que.size();
for(int i=0; i<size; i++){
if(i==size-1) depth++;
TreeNode *cur=que.front();
que.pop();
if(cur->left) que.push(cur->left);
if(cur->right) que.push(cur->right);
}
}
return depth;
}
111.二叉树的最小深度
题目
给定一个二叉树,找出其最小深度。
最小深度是从根节点到最近叶子节点的最短路径上的节点数量。
说明:叶子节点是指没有子节点的节点。
思路
本来我想当然地认为,既然变成了求最小深度,那拿之前求最大深度的代码,直接将递归代码2(求高度)中的max改为min不就是求最小深度了吗?
试了一下,果然想当然了,因为如果直接改为min,会出现一种情况,一个节点的左孩子为空,右孩子不为空,那么该节点不是叶节点,求高度不能按这个节点算,可是直接改为min的话就变成了按这个节点算高度,导致用例2中最小高度求得是1,显然是错误的。
因此,只能将左孩子、右孩子中有一方为空的情况区分出来,一方为空的话就接着求另一方的高度,如果两方都不为空再用1+min(getHeight(node->left), getHeight(node->right))求当前节点的最小高度。
当然,本题使用递归求深度也可以,只需要访问本节点时,判断一下该节点是否为叶子节点,若为叶子节点,由原先的将当前深度与最大深度的较大值赋给最大深度改为:将当前深度与最小深度的较小值赋给最小深度,就可以了。
最后,迭代法仍然使用层序遍历,过于简单不再赘述。
代码
递归(求高度)
int getHeight(TreeNode* node){
if(node==nullptr) return 0;
if(node->left==nullptr&&node->right!=nullptr){
return 1+getHeight(node->right);
}else if(node->left!=nullptr&&node->right==nullptr){
return 1+getHeight(node->left);
}else{
return 1+min(getHeight(node->left), getHeight(node->right));
}
}
int minDepth(TreeNode* root) {
return getHeight(root);
}
递归(求深度)
class Solution {
private:
int result;
void getdepth(TreeNode* node, int depth) {
// 函数递归终止条件
if (node == nullptr) {
return;
}
// 中,处理逻辑:判断是不是叶子结点
if (node -> left == nullptr && node->right == nullptr) {
result = min(result, depth);
}
if (node->left) { // 左
getdepth(node->left, depth + 1);
}
if (node->right) { // 右
getdepth(node->right, depth + 1);
}
return ;
}
public:
int minDepth(TreeNode* root) {
if (root == nullptr) {
return 0;
}
result = INT_MAX;
getdepth(root, 1);
return result;
}
};
迭代(层序遍历)
int minDepth(TreeNode* root) {
if(root==NULL) return 0;
int depth=0;
queue<TreeNode*> que;
que.push(root);
while(!que.empty()){
int size=que.size();
for(int i=0; i<size; i++){
TreeNode *tempNode=que.front();
que.pop();
if(tempNode->left==NULL&&tempNode->right==NULL){
return ++depth;
}
if(tempNode->left) que.push(tempNode->left);
if(tempNode->right) que.push(tempNode->right);
}
depth++;
}
return 0;
}
222.完全二叉树的节点个数
题目
给你一棵 完全二叉树 的根节点 root ,求出该树的节点个数。
完全二叉树 的定义如下:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层,则该层包含 1~ 2h 个节点。
思路
对于普通二叉树,三种遍历都可以直接统计出节点个数,但是题中已经说了这是完全二叉树,那肯定不能按常规的遍历来统计节点个数(面试时按常规的统计估计会直接G)。完全二叉树有个特殊的情况就是“满二叉树”,对于高度为n的满二叉树,节点个数就是“2^n-1”。
对于完全二叉树,可以看作由好几部分的“满二叉树组成”,而判断各个部分是不是“满二叉树”有个简单的办法,就是从当前部分的根节点出发,向左遍历到底统计出深度,向右遍历到底统计出深度,若左右深度相同,则该部分是满二叉树,否则,该部分不是满二叉树,需要继续细分。
有了上面这些知识后,我们开始递归三部曲:
函数参数与返回值:按照上面的思路,我们应该采用后序遍历,因为需要从底向上计算(只有这样才能保证计算的每部分都是满二叉树),显然参数只需要传入一个TreeNode节点,返回值为以TreeNode节点为根节点的该部分的节点个数。
递归终止条件:首先,遇到空节点肯定返回0,然后,就需要按照满二叉树的判断(该判断只针对完全二叉树有效)了,若判断该部分为满二叉树,直接利用公式2^n-1计算出该部分的节点个数,并返回;
单层递归的逻辑:若该部分不是满二叉树,则将该部分细分为左右两棵子树,继续递归求节点个数。
代码
int countNodes(TreeNode* root) {
if(root==nullptr) return 0;
int leftDepth=1, rightDepth=1;
TreeNode *leftNode=root->left;
TreeNode *rightNode=root->right;
while(leftNode){
leftDepth++;
leftNode=leftNode->left;
}
while(rightNode){
rightDepth++;
rightNode=rightNode->right;
}
if(leftDepth==rightDepth){
return(1<<leftDepth)-1; //2^n-1
}
return countNodes(root->left)+countNodes(root->right)+1;
今天好累,就只打一天的卡吧,溜了溜了。。。。。。