104.二叉树的最大深度
这道题在DAY18有写到过,但用的是非递归的层序遍历求最大深度。
这次可以用递归法写一下。
要确定当前遍历的参数、返回值,终止条件和递归逻辑。
参数可以在撰写函数的时候一点点补充,不急于一开始就写好全部参数。这里可以先用头节点作为传入参数。
返回值可以是当前节点的最大深度。
最大深度由该节点的左右节点最大深度+1得到。
如果当前节点为空,则返回0,作为终止条件。
开始递归:
/**
* 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) {
int result=0;
result=process(root);
return result;
}
int process(TreeNode* root){
if(root==nullptr) return 0;
int maxleft=process(root->left);
int maxright=process(root->right);
return 1+max(maxleft,maxright);
}
};
递归求最大深度的代码真的很简短很方便。
559. N 叉树的最大深度
跟上面的类似的思路,返回每个子节点最大深度加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) {
int result=0;
result=process(root);
return result;
}
int process(Node* root){
if(root==nullptr) return 0;
int M=0;
vector<Node*> ch=root->children;
int size=ch.size();
for(int i=0;i<size;++i){
M=max(M,process(ch[i]));
}
return M+1;
}
};
当然用非递归法层序遍历也能做,不再赘述。
111.二叉树的最小深度
当然DAY18已经用层序遍历写过,主要思路是在从上往下遍历每一层每个节点的时候找当前层是否有叶节点,如果有就直接返回当前层数作为最小深度。
今天来看递归写法:
需要知道递归过程的参数,返回值,终止条件。
参数可以先设置成头节点,
返回值是当前节点的最小深度?(后来发现不对)
终止条件是当前节点为空,返回0。
如果直接把返回值写成1+min(leftmin,rightmin),就会发现其实不对。
因为会有这种情况的出现:
借用了测试用例2的图来说明,直接求min可能会有类似图上这种,某个节点的左子或者右子为空,但该节点还不是叶节点,那么此时程序会把这种节点的左右最小深度直接算作0.
于是我突发奇想,如果要避免这种情况的话,首先确认这个节点不是叶节点,然后排除这种左右子中有一个深度为零的情况不就可以了吗?
具体思路是:
如果是空节点照常返回深度0.
如果该节点左右子有一个为空(或者全为空),就返回1+左右最大深度。因为这时候该节点的深度还是按照最大深度来算,才是他的实际深度。
如果该节点左右子都不为空,顺理成章返回他左右节点最小深度+1就可以了.
(该节点是叶节点的情况可以包括在第二种条件中,因为这时候左右都为0,返回的max也是0,符合预期。)
AC上代码:
/**
* 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) {
return process(root);
}
int process(TreeNode* root){
if(root==nullptr) return 0;
if(root->left==nullptr && root->right==nullptr) return 1;//这句话注释掉也能过
int L=process(root->left);
int R=process(root->right);
if(L!=0 && R!=0){
return 1+min(R,L);
}
return 1+max(R,L);
}
};
222 完全二叉树的节点个数
(完全二叉树和满二叉树定义不同,我一开始把这两个想混了)
完全二叉树 的定义如下:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层,则该层包含 1~ 2^h 个节点。
第一反应是可以层序遍历(我真的写了太多遍层序遍历的模板了导致下意识就会想用这个方法)数节点个数。
也可以用深度遍历数节点个数,递归和非递归方法。
是不是还可以有更简便的无需全部遍历?
既然是完全二叉树,那么前n-1层的节点数一定是2^i个,只需要遍历最后一层的节点就可以了。(但是要怎么做到??感觉很麻烦啊)
先写了一个层序遍历的:
/**
* 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) {
queue<TreeNode*> myque;
if(root==nullptr) return 0;
int result=0;
myque.push(root);
while(myque.empty()==0){
int n=myque.size();
result+=n;
while(n--){
TreeNode* t= myque.front();
myque.pop();
if(t->left) myque.push(t->left);
if(t->right) myque.push(t->right);
}
}
return result;
}
};
迭代层序遍历的时空复杂度都是N.
前序遍历递归:
/**
* 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) {
int result=0;
process(root,result);
return result;
}
void process(TreeNode* root, int& result){
if(root==nullptr) return;
result++;
process(root->left,result);
process(root->right,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 countNodes(TreeNode* root) {
int leftnode=0,rightnode=0;
if(root==nullptr) return 0;
TreeNode* L=root->left;
TreeNode* R=root->right;
while(L!=nullptr){
++leftnode;
L=L->left;
}
while(R!=nullptr){
++rightnode;
R=R->right;
}
if(leftnode==rightnode) return (2<<leftnode)-1;
int l_num,r_num;
l_num=countNodes(root->left);
r_num=countNodes(root->right);
return l_num+r_num+1;
}
};
odk,利用完全二叉树性质递归也需要二刷多练练