目录
一、做题心得
今天是代码随想录打卡的第14天,学习的是二叉树部分的part2。今天的题目运用到了不少昨天的知识,包括递归的思想,层序遍历的实现(昨天打卡有个模板),栈与队列的应用等等。整体而言,迭代的难度都不算大,但是递归思路可能不太容易理解,等会会对此进行一下分析。
话不多说,直接步入正题。
二、题目与题解
题目一:226.翻转二叉树
题目链接
给你一棵二叉树的根节点
root
,翻转这棵二叉树,并返回其根节点。示例 1:
输入:root = [4,2,7,1,3,6,9] 输出:[4,7,2,9,6,3,1]示例 2:
输入:root = [2,1,3] 输出:[2,3,1]示例 3:
输入:root = [] 输出:[]提示:
- 树中节点数目范围在
[0, 100]
内-100 <= Node.val <= 100
题解:1:BFS
这个题的要求就是从右往左的层序遍历,这就与昨天层序遍历(模板题)的思路一样,只不过先进的左节点得后出,只需要将存储树的节点queue改成stack既可,就能实现先进后出,进而实现从右往左的层序遍历。当然,这道题也可以直接用queue,只需要改成右节点先进队列既可,这样就是经典的BFS解法,大家可以去尝试一下。
不会层序遍历BFS的可以看看昨天打卡整理的模板题:【代码随想录训练营第42期 Day13打卡 二叉树的遍历-- LeetCode 144. 二叉树的前序遍历 94. 二叉树的中序遍历 145. 二叉树的后序遍历 102. 二叉树的层序遍历-CSDN博客
这里给出BFS思路(其实用queue来实现更纯粹,这里只是提供一下这个思路)的代码:
class Solution {
public:
TreeNode* invertTree(TreeNode* root) {
stack<TreeNode*> st;
if (root == nullptr) return root;
if (root != nullptr) st.push(root);
while (!st.empty()) {
int size = st.size(); //标记当前层的大小(节点数)
for(int i = 0; i < size; i++) {
TreeNode* node = st.top(); //当前节点
st.pop();
TreeNode* temp = node->left; //临时节点,用于交换当前节点node的左右孩子
node->left = node->right;
node->right = temp;
if(node->left) st.push(node->left); //进栈:先左后右。出栈相反
if(node->right) st.push(node->right);
}
}
return root;
}
};
注意与昨天层序遍历不同的地方:这里返回值类型为TreeNode* ,不是单独开个数组存储。
题解2:递归
递归的思路其实也简单,就是先对与根节点而言,交换左右孩子的位置,然后分别对左右孩子进行同样的操作,一直往后遍历交换左右孩子直到终止。
class Solution {
public:
TreeNode* invertTree(TreeNode* root) {
if (root == nullptr) return root; //终止条件
TreeNode* temp = root->left; //交换根的左右孩子
root->left = root->right;
root->right = temp;
root->left = invertTree(root->left); //递归;对根的左右孩子进行相同操作
root->right = invertTree(root->right);
return root;
}
};
题目二:101. 对称二叉树
题目链接
给你一个二叉树的根节点
root
, 检查它是否轴对称。示例 1:
输入:root = [1,2,2,3,4,4,3] 输出:true示例 2:
输入:root = [1,2,2,null,3,null,3] 输出:false提示:
- 树中节点数目在范围
[1, 1000]
内-100 <= Node.val <= 100
题解1:BFS
这个题也是用到的BFS的思想。从队列中取出两个节点(leftnode和 rightnode
),这两个节点是当前待检查的一对对称节点。(外层两对称以及内层两对称都能表示)
由于昨天对于层序遍历的思想有了具体描述,这里直接上代码:
class Solution {
public:
bool isSymmetric(TreeNode* root) {
queue<TreeNode*> q;
q.push(root->left);
q.push(root->right);
while(!q.empty()){
TreeNode* leftnode=q.front();
q.pop();
TreeNode* rightnode=q.front();
q.pop();
if(leftnode == nullptr && rightnode == nullptr) continue;
if((leftnode == nullptr && rightnode != nullptr) || (leftnode != nullptr && rightnode == nullptr) || leftnode->val != rightnode->val) return false;
q.push(leftnode->left); //外层
q.push(rightnode->right);
q.push(leftnode->right); //内层
q.push(rightnode->left);
}
return true;
}
};
题解2:递归
我们要自己定义一个函数,来比较左右子树是否对称。使用递归,首先要确定终止条件,表示各种可直接得到结果的特殊情况,再对于一般情况进行递归。
代码及详细思路如下:
class Solution {
public:
bool compare(TreeNode* left, TreeNode* right) { //比较左右子树left,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;
//递归
else {
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 true;
return compare(root->left, root->right);
}
};
题目三:104.二叉树的最大深度
题目链接
给定一个二叉树
root
,返回其最大深度。二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。
示例 1:
输入:root = [3,9,20,null,null,15,7] 输出:3示例 2:
输入:root = [1,null,2] 输出:2提示:
- 树中节点的数量在
[0, 104]
区间内。-100 <= Node.val <= 100
题解:递归
没什么好说的,直接一个简单的递归。
class Solution {
public:
int maxDepth(TreeNode* root) {
if (root == 0) return 0; //根节点为空时,同时也是作为递归的终止条件
return max(maxDepth(root->left),maxDepth(root->right))+1; //使用递归:二叉树的最大深度为根节点的左右子树深度的较大者+1
}
};
题目四:111.二叉树的最小深度
题目链接
给定一个二叉树,找出其最小深度。
最小深度是从根节点到最近叶子节点的最短路径上的节点数量。
说明:叶子节点是指没有子节点的节点。
示例 1:
输入:root = [3,9,20,null,null,15,7] 输出:2示例 2:
输入:root = [2,null,3,null,4,null,5,null,6] 输出:5提示:
- 树中节点数的范围在
[0, 105]
内-1000 <= Node.val <= 1000
题解一:BFS
再次套用BFS二叉树层序遍历模板。这个题需要注意的就是depth的使用(用来记录深度),以及遍历终止的条件--遍历的某个节点左子树和右子树都为空。
class Solution {
public:
int minDepth(TreeNode* root) {
if (root == NULL) return 0;
int depth = 0;
queue<TreeNode*> q; //使用队列进行BFS,从而实现层序遍历
q.push(root);
while(!q.empty()) {
int size = q.size(); //size记录每层节点个数
depth++; //记录最小深度,从根节点记作depth=1
for (int i = 0; i < size; i++) {
TreeNode* node = q.front();
q.pop();
if (node->left) q.push(node->left); //先进先出
if (node->right) q.push(node->right);
if (!node->left && !node->right) { // 当左右孩子都为空的时候,说明是最低点的一层了,退出
return depth;
}
}
}
return depth;
}
};
题解二:递归
注意这个题和上一道很相似,但不能直接套用。因为只有左子树或者右子树的话,最小值就恒定为0,也就是说不能直接一步到位,我们必须得考虑左子树或者右子树为空的情况。
代码如下:
class Solution {
public:
int minDepth(TreeNode* root) {
if (root == nullptr) return 0; //递归终止条件(root为空的特殊情况)
//递归(3种情况)
if (root->left == nullptr && root->right != nullptr) { //左子树为空,最小深度就是右子树的最小深度+1
return minDepth(root->right) + 1;
}
if (root->left != nullptr && root->right == nullptr) { //右子树为空,最小深度就是左子树的最小深度+1
return minDepth(root->left) + 1;
}
//如果当前节点的左右子树都不为空,则取左右子树最小深度的较小值+1
return min(minDepth(root->left), minDepth(root->right)) + 1;
}
};
三、小结
今天的打卡到此也就结束了,明天继续加油。最后,我是算法小白,但也希望终有所获。