「代码随想录算法训练营」第十一天 | 二叉树 part1
二叉树的基本知识
链接:https://programmercarl.com/二叉树理论基础.html
要点:
- 深度优先遍历
- 前序遍历(递归法,迭代法)
- 中序遍历(递归法,迭代法)
- 后序遍历(递归法,迭代法)
- 广度优先遍历
- 层次遍历(迭代法)
由于栈就是递归的一种实现结构,因此前中后序遍历的逻辑可以借助栈使用递归的方式来实现。
由于队列先进先出的特点,广度优先遍历一般使用队列来实现。
递归的思想:
每次写递归,要按照三要素去写:
- 确定递归函数的参数和返回值。
- 确定终止条件。
- 确定单层递归的逻辑。
下面开始具体的完成算法题目。
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
来存储每层最左边的元素,遍历每层元素时,将leftmost
的next
指向其后面一个元素,并更新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; } };
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?