算法day13|226.翻转二叉树、101. 对称二叉树、104.二叉树的最大深度、111.二叉树的最小深度
226.翻转二叉树
第一次做没做出来,看了卡哥的视频,我很疑惑:翻转和前中后序遍历有什么关系呢?其实,所谓的遍历顺序,也就是处理的顺序,其目的不在于把它遍历出来,而是给出一个等待处理的顺序或者说将二叉树转换成了类似于数组的结构,数组内的元素就按二叉树的前中后序来排列,这样就能使得二叉树的结点能够有序地被处理。具体代码如下:
class Solution {
public:
TreeNode* invertTree(TreeNode* root) {
if(root==nullptr)
return root;
swap(root->left,root->right);
invertTree(root->left);
invertTree(root->right);
return root;
}
};
用前序遍历的方式来有序地获取二叉树的元素。
有一点需要注意,root既是根节点,又是函数的参数。实际上的root一直待在原位,根本没有移动(根节点显然是不应该移动的);而root又作为参数,在形式上好像是一个指针,跟随来到各个结点。其实,对于非根结点来说,root只是一个形参,实参还是这个结点本身。而root的实参一直都是根节点,而不过是作为形参被各个结点借用。所以,只有在第一次递归的时候,root才是真实的root,其他时候都是其他结点的形参。
对于swap()函数,应该默认不限制数据类型。
另外,后序遍历,只是改了一下swap的位置:
invertTree(root->left);
invertTree(root->right);、
swap(root->left,root->right);
而中序遍历就不一样了,两个都是left(自己思考过程):
invertTree(root->left);
swap(root->left,root->right);
invertTree(root->left);
101. 对称二叉树
对于收集孩子信息,向上一层返回的题目,我们需要用后续遍历:
class Solution {
public:
bool compare(TreeNode*left,TreeNode*right)
{
if(left==nullptr&&right!=nullptr)
return false;
else if(left!=nullptr&&right==nullptr)
return false;
else if(left==nullptr&&right==nullptr)
return true;
else if(left->val!=right->val)
return false;
bool outside=compare(left->left,right->right);
bool inside=compare(left->right,right->left);
return outside&&inside;
}
bool isSymmetric(TreeNode* root) {
if(root!=nullptr)
return compare(root->left,root->right);
else
return false;
}
};
总体思路:采用递归的方式,三步走:
- 返回值和参数:返回值是bool,参数肯定是两侧对称的结点。一开始的结点往往是根节点附近的,本题的递归是由根节点的左右结点开始的
- 终止条件:就是**退出该递归的条件,**根据题目要求或隐含条件(基本是null啥的),提供递归的一个相当于是异常出口
- 单层递归逻辑(每个结点都做好了,整体自然就好了):对于单层递归,也就是针对于每一个结点,我们采用后续遍历的处理顺序(不用害怕!单层递归的时候我们只需要考虑某一个的逻辑就可以了!),先将左孩子代入递归,再将右孩子代入递归,最后再回到自己结点的判断。由于这道题结点的判断肯定是要结合左右孩子的,所以必须后序。
104.二叉树的最大深度
理解了上面的题目,这道题就不是很难了,第一次就做出来了。具体代码如下:
class Solution {
public:
void countNumber(TreeNode* root,int &count)
{
if(root==nullptr)
return;
count++;
int count1=count,count2=count;
countNumber(root->left,count1);
countNumber(root->right,count2);
count=count1>count2?count1:count2;
}
int maxDepth(TreeNode* root) {
int count=0;
if(root!=nullptr)
countNumber(root,count);
return count;
}
};
总体思路:采用递归的方式,三步走即可。这题依然是后序,需要先让左右孩子递归,得到它们的节点值,然后往上传递给当前值。
111.二叉树的最小深度
比最大深度稍微难了点,具体代码如下:
class Solution {
public:
void countNumber(TreeNode* root,int&count)
{
if(root==nullptr)
return;
count++;
int count1=count,count2=count;
countNumber(root->left,count1);
countNumber(root->right,count2);
if(count1==count&&count2!=count)
count=count2;
else if(count2==count&&count1!=count)
count=count1;
else if(count1==count&&count2==count)
return;
else
count=count1<count2?count1:count2;
}
int minDepth(TreeNode* root) {
int count=0;
if(root!=nullptr)
countNumber(root,count);
return count;
}
};
与求最大深度相比,求最小深度不同之处在于——需要判断其左孩子或有孩子是否为空。如果是空的,说明这一侧没有孩子节点了,所以只能取另一侧的count值。只有当两侧都不为空,我们才能取两个count中的最小值作为当前结点的结果,而求最大深度是不需要考虑这些问题的。