「代码随想录算法训练营」第十一天 | 二叉树 part1

news/2024/9/13 11:29:25/文章来源:https://www.cnblogs.com/frontpen/p/18303686

二叉树的基本知识

链接:https://programmercarl.com/二叉树理论基础.html

要点:

  • 深度优先遍历
    • 前序遍历(递归法,迭代法)
    • 中序遍历(递归法,迭代法)
    • 后序遍历(递归法,迭代法)
  • 广度优先遍历
    • 层次遍历(迭代法)

由于栈就是递归的一种实现结构,因此前中后序遍历的逻辑可以借助栈使用递归的方式来实现。
由于队列先进先出的特点,广度优先遍历一般使用队列来实现。

递归的思想:

每次写递归,要按照三要素去写:

  1. 确定递归函数的参数和返回值。
  2. 确定终止条件。
  3. 确定单层递归的逻辑。

下面开始具体的完成算法题目。

144. 二叉树的前序遍历

题目链接:https://leetcode.cn/problems/binary-tree-preorder-traversal/
题目难度:简单
文章讲解:https://programmercarl.com/二叉树的递归遍历.html
视频讲解:https://www.bilibili.com/video/BV1Wh411S7xt
题目状态:通过

递归思路:

使用递归的三要素完成递归操作,通过代码就可以看明白。

代码实现:

/*** 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:void traversal(TreeNode *root, vector<int> &res) {if(root == nullptr) return;res.push_back(root->val);traversal(root->left, res);traversal(root->right, res);}vector<int> preorderTraversal(TreeNode* root) {vector<int> res;traversal(root, res);return res;}
};

栈的思路:

先将根结点放入栈中,然后将右孩子加入栈,再加入左孩子。

为什么要先加入右孩子,在加入左孩子呢?因为这样出栈的时候才是中左右的顺序(可以看上图理解)。

代码实现:

/*** 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:vector<int> preorderTraversal(TreeNode* root) {stack<TreeNode *> st;vector<int> res;if(root == nullptr) return res;st.push(root);while(!st.empty()) {TreeNode *node = st.top();st.pop();res.push_back(node->val);if(node->right) st.push(node->right);if(node->left) st.push(node->left);}return res;}
};

145. 二叉树的后序遍历

题目链接:https://leetcode.cn/problems/binary-tree-postorder-traversal/

递归思路和上面一样,甚至代码都不太变,直接看代码:

/*** 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:void traversal(TreeNode *root, vector<int> &res) {if(root == nullptr) return;traversal(root->left, res);traversal(root->right, res);res.push_back(root->val);}vector<int> postorderTraversal(TreeNode* root) {vector<int> res;traversal(root, res);return res;}
};

栈的思想:

将前面前序遍历的进栈顺序“中->右->左”改变一下,变为“中->左->右”,此时出栈的顺序就是“中->右->左”,之后在反转一下,变为“左->右->中”即可。

代码实现:

/*** 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:vector<int> postorderTraversal(TreeNode* root) {stack<TreeNode *> st;vector<int> res;if(root == nullptr) return res;st.push(root);while(!st.empty()) {TreeNode *node = st.top();st.pop();res.push_back(node->val);if(node->left) st.push(node->left);if(node->right) st.push(node->right);}reverse(res.begin(), res.end());return res;}
};

94. 二叉树的中序遍历

题目链接:https://leetcode.cn/problems/binary-tree-inorder-traversal/

递归代码实现:

/*** 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:void traversal(TreeNode *root, vector<int> &res) {if(root == nullptr) return;traversal(root->left, res);res.push_back(root->val);traversal(root->right, res);}vector<int> inorderTraversal(TreeNode* root) {vector<int> res;traversal(root, res);return res;}
};

栈的思路:

采用指针将左孩子全部压入栈,再遍历出来;之后采用指针将右孩子全部压入栈,再遍历出来。

代码实现:

/*** 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:vector<int> inorderTraversal(TreeNode* root) {vector<int> res;stack<TreeNode *> st;TreeNode *cur = root;while(cur != nullptr || !st.empty()) {if(cur != nullptr) {st.push(cur);cur = cur->left;} else {cur = st.top();st.pop();res.push_back(cur->val);cur = cur->right;}}return res;}
};

102. 二叉树的层序遍历

题目链接:https://leetcode.cn/problems/binary-tree-level-order-traversal/
题目难度:中等
文章讲解:https://programmercarl.com/0102.二叉树的层序遍历.html
视频讲解:https://www.bilibili.com/video/BV1GY4y1u7b2
题目状态:通过

思路:

利用队列实现层序遍历,并通过size来判断该层是否已经输出完毕,并在输出每一层的某个元素的时候,将该元素的左右孩子压入队列中,直到队列为空,整个循环完毕,层序遍历结束。

代码实现:

/*** 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:vector<vector<int>> levelOrder(TreeNode* root) {vector<vector<int>> res;queue<TreeNode *> que;if(root != nullptr) que.push(root);while(!que.empty()) {int size = que.size();vector<int> vec;while(size--) {TreeNode *node = que.front();que.pop();vec.push_back(node->val);if(node->left) que.push(node->left);if(node->right) que.push(node->right);}res.push_back(vec);}return res;}
};

107. 二叉树的层次遍历II

题目链接:https://leetcode.cn/problems/binary-tree-level-order-traversal-ii/
题目难度:中等
文章讲解:https://programmercarl.com/0102.二叉树的层序遍历.html
视频讲解:https://www.bilibili.com/video/BV1GY4y1u7b2
题目状态:通过

思路:

102.二叉树的层序遍历的思路来,只是在最后反转一下结果即可。

代码实现:

/*** 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:vector<vector<int>> levelOrderBottom(TreeNode* root) {vector<vector<int>> res;queue<TreeNode *> que;if(root != nullptr) que.push(root);while(!que.empty()) {int size = que.size();vector<int> vec;while(size--) {TreeNode *node = que.front();que.pop();vec.push_back(node->val);if(node->left) que.push(node->left);if(node->right) que.push(node->right);}res.push_back(vec);}reverse(res.begin(), res.end());return res;}
};

199. 二叉树的右视图

题目链接:https://leetcode.cn/problems/binary-tree-right-side-view/
题目难度:中等
文章讲解:https://programmercarl.com/0102.二叉树的层序遍历.html
视频讲解:https://www.bilibili.com/video/BV1GY4y1u7b2
题目状态:通过

个人思路:

同样使用层序遍历,不同的是在每层遍历的时候,只需要把每层最后一个元素的值压入数组中,最后返回这个数组。

代码实现:

/*** 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:vector<int> rightSideView(TreeNode* root) {queue<TreeNode *> que;vector<int> vec;if(root != nullptr) que.push(root);while(!que.empty()) {int size = que.size();for(int i = 0; i < size; ++i) {TreeNode *node = que.front();que.pop();if(i == size - 1) vec.push_back(node->val);if(node->left) que.push(node->left);if(node->right) que.push(node->right);}}return vec;}
};

637. 二叉树的层平均值

题目链接:https://leetcode.cn/problems/average-of-levels-in-binary-tree/
题目难度:简单
文章讲解:https://programmercarl.com/0102.二叉树的层序遍历.html
视频讲解:https://www.bilibili.com/video/BV1GY4y1u7b2
题目状态:通过

个人思路:

依旧是层序遍历,在遍历每一层时记录该层的个数以及该层的和,最后求得平均数,返回在一个数组中。

代码实现:

/*** 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:vector<double> averageOfLevels(TreeNode* root) {vector<double> res;queue<TreeNode *> que;if(root != nullptr) que.push(root);while(!que.empty()) {int size = que.size();int len = size;double sum = 0; while(size--) {TreeNode *node = que.front();que.pop();sum += node->val;if(node->left) que.push(node->left);if(node->right) que.push(node->right);}res.push_back(sum / len);}return res;}
};

429. N 叉树的层序遍历

题目链接:https://leetcode.cn/problems/n-ary-tree-level-order-traversal/
题目难度:中等
文章讲解:https://programmercarl.com/0102.二叉树的层序遍历.html
视频讲解:https://www.bilibili.com/video/BV1GY4y1u7b2
题目状态:通过

个人思路:

加个for循环,将元素的所有孩子都加入队列中。

代码实现:

/*
// 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:vector<vector<int>> levelOrder(Node* root) {vector<vector<int>> res;queue<Node *> que;if(root != nullptr) que.push(root);while(!que.empty()) {int size = que.size();vector<int> vec;while(size--) {Node *node = que.front();que.pop();vec.push_back(node->val);for(int i = 0; i < node->children.size(); ++i) {if(node->children[i]) que.push(node->children[i]);}}res.push_back(vec);}return res;}
};

515. 在每个树行中找最大值

题目链接:https://leetcode.cn/problems/find-largest-value-in-each-tree-row/
题目难度:中等
文章讲解:https://programmercarl.com/0102.二叉树的层序遍历.html
视频讲解:https://www.bilibili.com/video/BV1GY4y1u7b2
题目状态:通过

个人思路:

加个max,若该层有比max大的元素,该元素的值就是max,最后在数组中存入该层的max即可。

代码实现:

/*** 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:vector<int> largestValues(TreeNode* root) {queue<TreeNode *> que;vector<int> res;if(root != nullptr) que.push(root);while(!que.empty()) {int size = que.size();int max = INT_MIN;while(size--) {TreeNode *node = que.front();que.pop();max = max > node->val ? max : node->val;if(node->left) que.push(node->left);if(node->right) que.push(node->right);}res.push_back(max);}return res;}
};

116. 填充每个节点的下一个右侧节点指针

题目链接:https://leetcode.cn/problems/populating-next-right-pointers-in-each-node/
题目难度:中等
文章讲解:https://programmercarl.com/0102.二叉树的层序遍历.html
视频讲解:https://www.bilibili.com/video/BV1GY4y1u7b2
题目状态:通过

个人思路:

定义一个leftmost来存储每层最左边的元素,遍历每层元素时,将leftmostnext指向其后面一个元素,并更新leftmost为当前元素,直到该层遍历完。

代码实现:

/*
// Definition for a Node.
class Node {
public:int val;Node* left;Node* right;Node* next;Node() : val(0), left(NULL), right(NULL), next(NULL) {}Node(int _val) : val(_val), left(NULL), right(NULL), next(NULL) {}Node(int _val, Node* _left, Node* _right, Node* _next): val(_val), left(_left), right(_right), next(_next) {}
};
*/class Solution {
public:Node* connect(Node* root) {queue<Node *> que;Node *leftmost;if(root != nullptr) {que.push(root);leftmost = root;}while(!que.empty()) {int size = que.size();for(int i = 0; i < size; ++i) {Node *node = que.front();que.pop();if(i > 0) {leftmost->next = node;}leftmost = node;if(node->left) que.push(node->left);if(node->right) que.push(node->right);}}return root;}
};

117. 填充每个节点的下一个右侧节点指针II

题目链接:https://leetcode.cn/problems/populating-next-right-pointers-in-each-node-ii/
题目难度:中等
文章讲解:https://programmercarl.com/0102.二叉树的层序遍历.html
视频讲解:https://www.bilibili.com/video/BV1GY4y1u7b2
题目状态:通过

和上一次思路一样,甚至实现代码都一样。

代码实现:

/*
// Definition for a Node.
class Node {
public:int val;Node* left;Node* right;Node* next;Node() : val(0), left(NULL), right(NULL), next(NULL) {}Node(int _val) : val(_val), left(NULL), right(NULL), next(NULL) {}Node(int _val, Node* _left, Node* _right, Node* _next): val(_val), left(_left), right(_right), next(_next) {}
};
*/class Solution {
public:Node* connect(Node* root) {queue<Node *> que;Node *leftmost;if(root != nullptr) {que.push(root);leftmost = root;}while(!que.empty()) {int size = que.size();for(int i = 0; i < size; ++i) {Node *node = que.front();que.pop();if(i > 0) {leftmost->next = node;}leftmost = node;if(node->left) que.push(node->left);if(node->right) que.push(node->right);}}return root;}
};

104. 二叉树的最大深度

题目链接:https://leetcode.cn/problems/maximum-depth-of-binary-tree/
题目难度:简单
文章讲解:https://programmercarl.com/0102.二叉树的层序遍历.html
视频讲解:https://www.bilibili.com/video/BV1GY4y1u7b2
题目状态:通过

个人思路:

层序遍历,记录有几层,层数就是二叉树的最大深度。

代码实现:

/*** 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 high = 0;queue<TreeNode *> que;if(root != nullptr) que.push(root);while(!que.empty()) {int size = que.size();high++;while(size--) {TreeNode *node = que.front();que.pop();if(node->left) que.push(node->left);if(node->right) que.push(node->right);}}return high;}
};

111. 二叉树的最小深度

题目链接:https://leetcode.cn/problems/minimum-depth-of-binary-tree/
题目难度:简单
文章讲解:https://programmercarl.com/0102.二叉树的层序遍历.html
视频讲解:https://www.bilibili.com/video/BV1GY4y1u7b2
题目状态:通过

思路:

当一个节点既没有左孩子也没有右孩子时,这个节点就是叶子节点,而根结点到叶子节点中间的节点数就是两者之间的高度。

代码实现:

/*** 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) {int high = 0;queue<TreeNode *> que;if(root != nullptr) que.push(root);while(!que.empty()) {int size = que.size();high++;while(size--) {TreeNode *node = que.front();que.pop();if(node->left) que.push(node->left);if(node->right) que.push(node->right);if(!node->left && !node->right) return high;}}return high;}
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/744204.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

从0到1打造一个 WebRTC 应用

🧑‍💻 写在开头 点赞 + 收藏 === 学会🤣🤣🤣前言 2020 年初突如其来的新冠肺炎疫情让线下就医渠道几乎被切断,在此背景下,微医作为数字健康行业的领军者通过在线问诊等形式快速解决了大量急需就医人们的燃眉之急。而作为微医 Web 端在线问诊中重要的一环-医患之间…

K8S 中的 CRI、OCI、CRI shim、containerd

哈喽大家好,我是咸鱼。 好久没发文了,最近这段时间都在学 K8S。不知道大家是不是和咸鱼一样,刚开始学 K8S、Docker 的时候,往往被 CRI、OCI、CRI shim、containerd 这些名词搞得晕乎乎的,不清楚它们到底是干什么用的。所以今天,咸鱼打算借这篇文章来解释一下这些名词,帮…

通过手机去访问本地写的h5页面(使用同一个局域网)

主要流程为: 打开cmd,然后输入一行指令1.npm install http-server -g(全局安装http-server,前提是有node环境,并且手机和电脑用的是同一个局域网内)2.然后通过cmd进入到你放html文件的文件夹内 3.通过http-server指令开启服务,cmd就会提示:

Turtlebot3在ROS Gazebo中使用OpenCV检测并跟踪球体

原文链接:https://www.youtube.com/watch?v=Rw6ATkORRG8一个小巧的机器人在虚拟世界中敏捷地追踪着一个滚动的球体。Turtlebot3,一个搭载ROS操作系统的智能机器人,在Gazebo仿真环境中,利用OpenCV的神奇力量,展现出令人惊叹的视觉追踪能力。Turtlebot3的"眼睛"是…

Python循环控制

本文介绍了Python编程语言中关于for循环和if条件控制的一些基本使用。包含了单层循环的退出机制和多层循环的退出机制,使得我们在满足特定条件时,可以直接结束多层循环。技术背景 循环控制是每一门编程语言的基础,最常用的就是for循环和while循环。使用循环可以很大程度上简…

【C/C++】结构体内存对齐

结构体内存对齐详解 1、第一个成员在与结构体变量偏移量为0的地址处2、其他成员变量要偏移到 对齐数 的整数倍的地址处 ,注意 偏移是从结构体首地址处开始的。对齐数 取的是 编译器默认的一个对齐数 与 该成员大小 这个俩个数中的最小值。【VS中默认的值为8、Linux环境默认不设…

我不应该用JWT的!

一、前言 大家好呀,我是summo,之前有自学过Shrio框架,网上一搜就有SpringBoot整合Shrio+ JWT的文章,我是在学习Shrio框架的时候顺带学的JWT。后来我还看见有很多博主专门写文章介绍JWT,说这个东西的优点很多,安全性好、去中心化、方便啥的,我就把JWT也应用在我们自己的系…

OpenAI 曝新项目「草莓」,提升 AI 推理能力;智谱 AI 开源视频理解模型丨 RTE 开发者日报

开发者朋友们大家好:这里是 「RTE 开发者日报」 ,每天和大家一起看新闻、聊八卦。我们的社区编辑团队会整理分享 RTE(Real-Time Engagement) 领域内「有话题的新闻」、「有态度的观点」、「有意思的数据」、「有思考的文章」、「有看点的会议」,但内容仅代表编辑的个人观点…

2024-07-15 vue组件发布npm后,再使用,样式不见了?==》查看样式是否在dist包里,有的话应该就是样式没引用

哎,嗯。。。emmm。。。 好,问题就是这样的,最近写了vue组件打算上到npm,然后上是上了,但是样式却没有生效??左上角是组件样式本地调试的截图,可以看到是生效的,右上角的截图是我在别的项目引用了我写的这个库,结果样式却没有生效。 我打包后的文件列表如下: 注意:s…

centos8 内核升级教程 执行安装成功后 reboot

Centos 处理步骤 先设置DNS为114.114.114.114等 CentOS 8 升级内核到 6.9 步骤 **1 查看内核现状版本 4.18** [root@localhost yum.repos.d]# hostnamectl Static hostname: localhost.localdomain Icon name: computer-vm Chassis: vm Machine ID: 1c063b9ed186473e891a2fe6ac…

【笔记】Nmap工具原理探索

学习记录下计网原理的东西【笔记】Nmap工具原理探索 原文章:【THM】Nmap(Nmap工具使用简介)-学习 - Hekeatsll - 博客园 (cnblogs.com) Nmap是一款跨平台的开源端口扫描软件,它用来扫描计算机的开放端口,以确定运行的网络服务,并推断出计算机运行的操作系统 Nmap三种基本扫…

QUIC(更新中... ...)

本文档只记录我个人认为应该着重进行一下笔记的部分。 RFC QUIC 基本内容介绍在RFC 9000,加密的实现在9001,丢包检测和拥塞机制在9002。 简介 是由Google开发的一种基于UDP的传输层协议,旨在提高网络传输的性能和安全性。关键要素:UDP 443端口,将TLS 1.3内置在QUIC协议报文…