代码随想录算法训练营第14天
代码随想录算法训练营第14天 | 226.翻转二叉树,101.对称二叉树,104.二叉树的最大深度,111.二叉树的最小深度
一、刷题部分
1.1 226.翻转二叉树
- 原文链接:代码随想录
- 题目链接:226. 翻转二叉树 - 力扣(LeetCode)
1.1.1 题目描述
给你一棵二叉树的根节点 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.1.2 初见思路
直接看题解,加速刷题。
1.1.3 正式做题
本题就是按照某种遍历顺序将每个节点的左右孩子交换位置就可以。先序后序以及层序遍历都是可以的,中序遍历会出问题,画个图试一下就知道了。
使用先序遍历递归法,第一步确定函数参数和返回值,为了统一力扣的接口所以返回当前处理的节点,其实直接 void 也是不影响的。
TreeNode* invertTree(TreeNode* root);
然后确定终止条件:
if(!root) return root;
最后确定单层逻辑,使用先序遍历
swap(root->left, root->right);
invertTree(root->left);
invertTree(root->right);
之后复习一下之前练习的迭代法,同样使用先序遍历:
TreeNode* invertTree(TreeNode* root) {
if (!root) return root;
stack<TreeNode*> st;
st.push(root);
while (!st.empty()) {
TreeNode* cur = st.top();
st.pop();
swap(cur->left, cur->right);
if(cur->right) st.push(cur->right);
if(cur->left) st.push(cur->left);
}
return root;
}
1.1.4 遇到的困难
没有遇到困难。
1.1.5 本题总结
使用合适的遍历顺序将左右孩子交换。
1.2 101.对称二叉树
- 原文链接:代码随想录
- 题目链接:101. 对称二叉树 - 力扣(LeetCode)
1.2.1 题目描述
给你一个二叉树的根节点 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.2.2 初见思路
以根结点的孩子开始分成左右两个子树,然后就看两个子树的所有孩子是否刚好和另一边返过来,遍历一下就行。
直接看题解,加速刷题。
1.2.3 正式做题
题解和我的思路并不相同,将问题分成了递归的子问题,先判断子树是否是对称的,然后将信息返回给上层节点,从而继续判断是否对称。这显然是使用后序遍历比较合适了。具体来做是用两个指针分别在左右两边进行遍历,然后进行比较。
首先确定递归函数的参数和返回值:
bool compare(TreeNode* left, TreeNode* right);
然后确定终止条件,这题终止条件情况很多,不要漏:
if (left == NULL && right == NULL) return true;
else if (left != NULL && right == NULL) return false;
else if (left == NULL && right != NULL) return false;
else if (left->val != right->val) return false;
//最后剩下的情况就是左右指针都有且数值相同,那就不是终止的情况而是需要继续处理
....
return XXX
第三步就是处理单层递归的逻辑:
//先比较外侧孩子
bool outside = compare(left->left, right->right);
if(!outside) return false;//一侧不同立即返回false
//再比较内侧孩子
bool inside = compare(left->right, right->left);
return inside;
1.2.4 遇到的困难
还有迭代法的思路,看了一下录里的博客就过了,没有上手写。
1.2.5 本题总结
整体代码:
/**
* 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:
bool isSymmetric(TreeNode* root) {
return compare(root->left, root->right);
}
bool compare(TreeNode* left, TreeNode* right) {
if(left == NULL && right == NULL) return true;
else if((bool)left ^ (bool)right) return false;
else if(left->val != right->val) return false;
//先将几种最基础的退出条件写出来
bool flag = compare(left->left, right->right);
if(!flag) return false;
flag = compare(left->right, right->left);
return flag;
}
};
1.3 104.二叉树的最大深度
- 原文链接:代码随想录
- 题目链接:104. 二叉树的最大深度 - 力扣(LeetCode)
1.3.1 题目描述
给定一个二叉树 root
,返回其最大深度。
二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。
示例 1:
输入:root = [3,9,20,null,null,15,7]
输出:3
示例 2:
输入:root = [1,null,2]
输出:2
提示:
- 树中节点的数量在
[0, 104]
区间内。 -100 <= Node.val <= 100
1.3.2 初见思路
可以使用遍历的方式来统计高度,需要修改一些逻辑。
直接看题解,加速刷题。
1.3.3 正式做题
首先注意深度和高度的定义是不一样的,高度是越靠近根结点越大,深度是越靠近叶子节点越大。从 0 还是 从 1 开始这个不一定,看是计算边的条数还是节点的个数。
使用迭代法,第 1 步,确定参数和返回值:
int getDepth(Treenode* node);
第 2 步,确定终止条件:
if (node == 0) return 0;
第 3 步,写单层函数逻辑:
int leftDepth = getDepth(node->left);
int rightDepth = getDepth(node->right);
int depth = 1 + max(leftDepth, rightDepth);
return depth;
这其实是一个后序遍历。
1.3.4 遇到的困难
后面的回溯法 以及 迭代法 由于时间关系,一刷的时候就先跳过了。
1.3.5 本题总结
这类题目需要心里清楚使用什么样的遍历方式最好。
class Solution {
public:
int maxDepth(TreeNode* root) {
return getHeight(root);
}
int getHeight(TreeNode* cur) {
if(!cur) return 0;
return max(getHeight(cur->left), getHeight(cur->right)) + 1;
}
};
1.4 111.二叉树的最小深度
- 原文链接:代码随想录
- 题目链接:111. 二叉树的最小深度 - 力扣(LeetCode)
1.4.1 题目描述
给定一个二叉树,找出其最小深度。
最小深度是从根节点到最近叶子节点的最短路径上的节点数量。
说明:叶子节点是指没有子节点的节点。
示例 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
1.4.2 初见思路
能不能套用上一题的逻辑呢,就是将两个子树的最小高度返回上来再 +1。看起来没问题。快速看一下题解来验证一下吧。
1.4.3 正式做题
本题有个小坑,就是如果根结点的一个孩子是空的,另一个孩子不是空的,那么这里是不算最小深度的,因为题目的定义里要求从叶子节点出发。一个图示很好的说明了这一点:
开始递归三部曲:
- 确定递归函数的参数和返回值
int getDepth(TreeNode* node);
- 确定终止条件
if (!node) return 0;
- 确定单层递归逻辑
int leftDepth = getDepth(node->left);
int rightDepth = getDepth(node->right);
int result = 1 + min(leftDepth, rightDepth);
return result;
如果到这里就直接提交了,就会遇到上面说的小坑,
需要把单边空白的情况考虑进去。
int leftDepth = getDepth(node->left);
int rightDepth = getDepth(node->right);
if (node->left == NULL && node->right != NULL) {
return 1 + rightDepth;
}
if (node->left != NULL && node->right == NULL) {
return 1 + leftDepth;
}
int result = 1 + min(leftDepth, rightDepth);
return result;
1.4.4 遇到的困难
前序遍历、迭代法先跳过,二刷再看。
1.4.5 本题总结
class Solution {
public:
int minDepth(TreeNode* root) {
return getDepth(root);
}
int getDepth(TreeNode* node) {
if(!node) return 0;
int leftDepth = getDepth(node->left);
int rightDepth = getDepth(node->right);
if (node->left == NULL && node->right != NULL) {
return 1 + rightDepth;
}
if (node->left != NULL && node->right == NULL) {
return 1 + leftDepth;
}
int result = 1 + min(leftDepth, rightDepth);
return result;
}
};
二、总结与回顾
相当于对二叉树遍历进行了一些简单的应用,已经有点摸到门道的感觉了。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性