【LeetCode】9.二叉树系列——遍历

总目录:

LeetCode系列导航目录

 

0.理论基础

0.1如何遍历

 

0.2.如何写递归

三板斧

(1)确定入参和返回值,如果需要搜索全部范围则不需要返回值,如果搜到目标值就需立即返回的话就必须返回值;

(2)确定终止条件;

(3)确定本层逻辑,包括数据处理和调用自身函数实现递归;

0.3.递归版DFS

以前序遍历为例:

1     void traversal(TreeNode* cur, vector<int>& vec) {
2         if (cur == NULL) return;
3         vec.push_back(cur->val);    //
4         traversal(cur->left, vec);  //
5         traversal(cur->right, vec); //
6     }

0.4.迭代版DFS

前、中、后序的结构不太一样,需要具体顺序具体分析。尤其是中序遍历。

具体代码见下方。

0.5.迭代版BFS

层序遍历,一层一层地从左到右处理节点。

 1 class Solution {
 2 public:
 3     vector<vector<int>> levelOrder(TreeNode* root) {
 4         queue<TreeNode*> que;
 5         if (root != NULL) que.push(root);
 6         vector<vector<int>> result;
 7         while (!que.empty()) {
 8             int size = que.size();
 9             vector<int> vec;
10             // 这里一定要使用固定大小size,不要使用que.size(),因为que.size是不断变化的
11             for (int i = 0; i < size; i++) {
12                 TreeNode* node = que.front();
13                 que.pop();
14                 vec.push_back(node->val);
15                 if (node->left) que.push(node->left);
16                 if (node->right) que.push(node->right);
17             }
18             result.push_back(vec);
19         }
20         return result;
21     }
22 };
View Code

0.6.递归版BFS

输入层号,进行递归

 1 # 递归法
 2 class Solution {
 3 public:
 4     void order(TreeNode* cur, vector<vector<int>>& result, int depth)
 5     {
 6         if (cur == nullptr) return;
 7         if (result.size() == depth) result.push_back(vector<int>());
 8         result[depth].push_back(cur->val);
 9         order(cur->left, result, depth + 1);
10         order(cur->right, result, depth + 1);
11     }
12     vector<vector<int>> levelOrder(TreeNode* root) {
13         vector<vector<int>> result;
14         int depth = 0;
15         order(root, result, depth);
16         return result;
17     }
18 };
View Code

 

1.二叉树递归版前中后序遍历

1.1.问题描述

分别用递归实现二叉树的前中后序遍历

链接:

https://leetcode.cn/problems/binary-tree-preorder-traversal/

https://leetcode.cn/problems/binary-tree-inorder-traversal/

https://leetcode.cn/problems/binary-tree-postorder-traversal/

1.2.要点

递归三板斧、弄清楚根节点数据在哪个顺位被处理

1.3.代码实例

 1 class Solution {
 2 public:
 3     void recurve(vector<int>& vec,const TreeNode* root){
 4         if(root==NULL){
 5             return;
 6         }
 7         
 8         vec.push_back(root->val);
 9         recurve(vec,root->left);
10         recurve(vec,root->right);
11     }
12     vector<int> preorderTraversal(TreeNode* root) {
13         vector<int> vec;
14         if(root==NULL){
15             return vec;
16         }
17         recurve(vec,root);
18 
19         return vec;
20     }
21 };
View Code

 1 class Solution {
 2 public:
 3     void recurve(vector<int>& vec,const TreeNode* root){
 4         if(root==NULL){
 5             return;
 6         }
 7                 
 8         recurve(vec,root->left);
 9         vec.push_back(root->val);
10         recurve(vec,root->right);
11     }
12     vector<int> inorderTraversal(TreeNode* root) {
13         vector<int> vec;
14         if(root==NULL){
15             return vec;
16         }
17         recurve(vec,root);
18 
19         return vec;
20     }
21 };
View Code

 1 class Solution {
 2 public:
 3     void recurve(vector<int>& vec,const TreeNode* root){
 4         if(root==NULL){
 5             return;
 6         }
 7                 
 8         recurve(vec,root->left);        
 9         recurve(vec,root->right);
10         vec.push_back(root->val);
11     }
12     vector<int> postorderTraversal(TreeNode* root) {
13         vector<int> vec;
14         if(root==NULL){
15             return vec;
16         }
17         recurve(vec,root);
18 
19         return vec;
20     }
21 };
View Code

 

2.二叉树迭代版前中后序遍历

2.1.问题描述

分别用迭代实现二叉树的前中后序遍历

链接:同上一题

2.2.要点

用迭代法来遍历树较为少用,关键还是其对栈的运用技巧,如何保存中间变量。

递归的本质就是将中间过程压栈弹栈,迭代时使用栈来实现。

前序迭代,访问顺序和处理顺序一致:

(1)while迭代判断栈是否为空;

(2)取栈顶元素,处理它的数据;

(3)先入栈其右子节点,如果有;再入栈其左子节点,如果有。

中序迭代,访问顺序和处理顺序不一致:记住固定套路。

后序迭代,前序迭代是中左右,后序迭代是左右中。将前序迭代改一下变成中右左,然后将结果翻转一下即可。

2.3.代码实例

 1 class Solution {
 2 public:
 3     vector<int> preorderTraversal(TreeNode* root) {
 4         stack<TreeNode*> st;
 5         vector<int> result;
 6         if (root == NULL) return result;
 7         st.push(root);
 8         
 9         while (!st.empty()) {
10             TreeNode* node = st.top();                       //
11             st.pop();
12             result.push_back(node->val);
13             if (node->right) st.push(node->right);           // 右(空节点不入栈)
14             if (node->left) st.push(node->left);             // 左(空节点不入栈)
15         }
16         return result;
17     }
18 };
View Code

 1 class Solution {
 2 public:
 3     vector<int> inorderTraversal(TreeNode* root) {
 4         vector<int> result;
 5         stack<TreeNode*> st;
 6         TreeNode* cur = root;
 7 
 8         while (cur != NULL || !st.empty()) {
 9             if (cur != NULL) { // 指针来访问节点,访问到最底层
10                 st.push(cur); // 将访问的节点放进栈
11                 cur = cur->left;                //
12             } else {
13                 cur = st.top(); // 从栈里弹出的数据,就是要处理的数据(放进result数组里的数据)
14                 st.pop();
15                 result.push_back(cur->val);     //
16                 cur = cur->right;               //
17             }
18         }
19         
20         return result;
21     }
22 };
View Code

 1 class Solution {
 2 public:
 3     vector<int> postorderTraversal(TreeNode* root) {
 4         vector<int> vec;
 5         if(root==NULL){
 6             return vec;
 7         }
 8 
 9         stack<TreeNode*> nodeSt;
10         nodeSt.push(root);
11         TreeNode* cur=NULL;
12         while(!nodeSt.empty()){
13             cur=nodeSt.top();
14             nodeSt.pop();
15 
16             vec.push_back(cur->val);
17             if(cur->left!=NULL){nodeSt.push(cur->left);}
18             if(cur->right!=NULL){nodeSt.push(cur->right);}
19         }
20         reverse(vec.begin(),vec.end());
21         return vec;
22     }
23 };
View Code

 

3.二叉树的层序遍历,从上到下/从下到上

3.1.问题描述

给你二叉树的根节点 root ,返回其节点值的 层序遍历 。 (即逐层地,从左到右访问所有节点)。

链接:https://leetcode.cn/problems/binary-tree-level-order-traversal/

链接:https://leetcode.cn/problems/binary-tree-level-order-traversal-ii/

3.2.要点

层序的不同最后再处理

1迭代法

2递归法

3.3.代码实例

迭代法

 1 class Solution {
 2 public:
 3     vector<vector<int>> levelOrder(TreeNode* root) {
 4         queue<TreeNode*> que;
 5         if (root != NULL) que.push(root);
 6         vector<vector<int>> result;
 7         while (!que.empty()) {
 8             int size = que.size();
 9             vector<int> vec;
10             // 这里一定要使用固定大小size,不要使用que.size(),因为que.size是不断变化的
11             for (int i = 0; i < size; i++) {
12                 TreeNode* node = que.front();
13                 que.pop();
14                 vec.push_back(node->val);
15                 if (node->left) que.push(node->left);
16                 if (node->right) que.push(node->right);
17             }
18             result.push_back(vec);
19         }
20         return result;
21     }
22 };
View Code

递归版

 1 class Solution {
 2 public:
 3     void recurve(vector<vector<int>>& vec,TreeNode* root,int levelId){
 4         if(root==NULL){
 5             return;
 6         }        
 7         while(vec.size()<=levelId){
 8             vec.push_back(vector<int>());
 9         }
10         vec[levelId].push_back(root->val);
11         recurve(vec,root->left,levelId+1);
12         recurve(vec,root->right,levelId+1);
13     }
14     vector<vector<int>> levelOrder(TreeNode* root) {
15         vector<vector<int>> vec;
16         int levelId=0;
17         recurve(vec,root,0);
18         return vec;
19     }
20 };
View Code

 

4.二叉树的右视图

4.1.问题描述

给定一个二叉树的 根节点 root,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值。

 

 输入: [1,2,3,null,5,null,4] 输出: [1,3,4]

链接:https://leetcode.cn/problems/binary-tree-right-side-view/

4.2.要点

迭代版层序遍历,每层只取最后一个

4.3.代码实例

迭代版层序遍历

 1 class Solution {
 2 public:
 3     vector<int> rightSideView(TreeNode* root) {
 4         queue<TreeNode*> que;
 5         if (root != NULL) que.push(root);
 6         vector<int> result;
 7         while (!que.empty()) {
 8             int size = que.size();
 9             // 这里一定要使用固定大小size,不要使用que.size(),因为que.size是不断变化的
10             for (int i = 0; i < size; i++) {
11                 TreeNode* node = que.front();
12                 que.pop();
13                 if(i==(size-1)){
14                     result.push_back(node->val);
15                 }                
16                 if (node->left) que.push(node->left);
17                 if (node->right) que.push(node->right);
18             }
19         }
20         return result;
21     }
22 };
View Code

 

5.二叉树的各层平均值

5.1.问题描述

给定一个非空二叉树的根节点 root , 以数组的形式返回每一层节点的平均值。与实际答案相差 10-5 以内的答案可以被接受。

链接:https://leetcode.cn/problems/average-of-levels-in-binary-tree/

5.2.要点

求各层中节点之和后取平均值

1迭代式层序遍历

5.3.代码实例

迭代式层序遍历

 1 /**
 2  * Definition for a binary tree node.
 3  * struct TreeNode {
 4  *     int val;
 5  *     TreeNode *left;
 6  *     TreeNode *right;
 7  *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 8  *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 9  *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
10  * };
11  */
12 class Solution {
13 public:
14     vector<double> averageOfLevels(TreeNode* root) {
15         queue<TreeNode*> que;
16         if (root != NULL) que.push(root);
17 
18         vector<double> result;
19         double sum=0;
20         while (!que.empty()) {
21             int size = que.size();
22             sum=0;
23 
24             // 这里一定要使用固定大小size,不要使用que.size(),因为que.size是不断变化的
25             for (int i = 0; i < size; i++) {
26                 TreeNode* node = que.front();
27                 que.pop();
28 
29                 sum+=1.0*node->val;
30 
31                 if (node->left) que.push(node->left);
32                 if (node->right) que.push(node->right);
33             }
34 
35             result.push_back(sum/size);
36         }
37         return result;
38     }
39 };
View Code

 

6.N叉树的层序遍历

6.1.问题描述

给定一个 N 叉树,返回其节点值的层序遍历。(即从左到右,逐层遍历)。

树的序列化输入是用层序遍历,每组子节点都由 null 值分隔(参见示例)。

 

 链接:https://leetcode.cn/problems/n-ary-tree-level-order-traversal/

6.2.要点

处理每个节点的child集合,而不是左右子节点

1迭代式层序遍历

6.3.代码实例

迭代式层序遍历

 1 /*
 2 // Definition for a Node.
 3 class Node {
 4 public:
 5     int val;
 6     vector<Node*> children;
 7 
 8     Node() {}
 9 
10     Node(int _val) {
11         val = _val;
12     }
13 
14     Node(int _val, vector<Node*> _children) {
15         val = _val;
16         children = _children;
17     }
18 };
19 */
20 
21 class Solution {
22 public:
23     vector<vector<int>> levelOrder(Node* root) {
24         queue<Node*> que;
25         if (root != NULL) que.push(root);
26         vector<vector<int>> result;
27         while (!que.empty()) {
28             int size = que.size();
29             vector<int> vec;
30             // 这里一定要使用固定大小size,不要使用que.size(),因为que.size是不断变化的
31             for (int i = 0; i < size; i++) {
32                 Node* node = que.front();
33                 que.pop();
34                 vec.push_back(node->val);
35 
36                 for(Node*& child:node->children){
37                     if (child) que.push(child);
38                 }
39             }
40             result.push_back(vec);
41         }
42         return result;
43     }
44 };
View Code

 

7.在二叉树的每层找出最大值

7.1.问题描述

给定一棵二叉树的根节点 root ,请找出该二叉树中每一层的最大值。

链接:https://leetcode.cn/problems/find-largest-value-in-each-tree-row/

7.2.要点

1迭代式层序遍历

7.3.代码实例

 

8.填充每个节点的右侧节点

8.1.问题描述

给定一个 完美二叉树 ,其所有叶子节点都在同一层,每个父节点都有两个子节点。二叉树定义如下:

1 struct Node {
2   int val;
3   Node *left;
4   Node *right;
5   Node *next;
6 }

填充它的每个 next 指针,让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点,则将 next 指针设置为 NULL。
初始状态下,所有 next 指针都被设置为 NULL。

 

 
链接:https://leetcode.cn/problems/populating-next-right-pointers-in-each-node

链接:https://leetcode.cn/problems/populating-next-right-pointers-in-each-node-ii/

8.2.要点

1迭代式层序遍历

8.3.代码实例

 

9.二叉树的最大深度

9.1.问题描述

给定一个二叉树,找出其最大深度。

二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。

说明: 叶子节点是指没有子节点的节点。

示例:
给定二叉树 [3,9,20,null,null,15,7],
    3
   / \
  9  20
    /  \
   15   7
返回它的最大深度 3 。
链接:https://leetcode.cn/problems/maximum-depth-of-binary-tree

9.2.要点

1迭代式层序遍历,levelCnt++

9.3.代码实例

 

10.二叉树的最小深度

10.1.问题描述

给定一个二叉树,找出其最小深度。

最小深度是从根节点到最近叶子节点的最短路径上的节点数量。

说明:叶子节点是指没有子节点的节点。

 

 链接:https://leetcode.cn/problems/minimum-depth-of-binary-tree/

10.2.要点

遇到叶子节点就要比较一下深度最小值

1迭代式层序遍历,levelCnt++,与levelMin作比较

10.3.代码实例

 

11.翻转二叉树

11.1.问题描述

给你一棵二叉树的根节点 root ,翻转这棵二叉树,并返回其根节点。

链接:https://leetcode.cn/problems/invert-binary-tree/

11.2.要点

递归交换左右节点,不可使用中序遍历,可以使用前序和后序遍历。

11.3.代码实例

递归

 1 class Solution {
 2 public:
 3     TreeNode* invertTree(TreeNode* root) {
 4         if(root==NULL){
 5             return NULL;
 6         }
 7 
 8         TreeNode* tmp=root->left;
 9         root->left=root->right;
10         root->right=tmp;
11 
12         invertTree(root->left);
13         invertTree(root->right);
14 
15         return root;
16     }
17 };
View Code

 

12.遍历总结

12.1.遍历方式

策略上可以分为深度优先、广度优先,
具体实现上可以分为递归和迭代,迭代一般借助队列或栈。
深度优先的迭代实现方式较为麻烦,而且前、中、后的实现策略不一样,这一块需要特别练习。

 12.2实现

递归、栈迭代、队列迭代并不对立,都有各自的实现逻辑,具体实现例子可以参考

https://github.com/hitwzy/leetcode-master/blob/master/problems/0101.%E5%AF%B9%E7%A7%B0%E4%BA%8C%E5%8F%89%E6%A0%91.md

 

xxx.问题

xxx.1.问题描述

111

xxx.2.要点

222

xxx.3.代码实例

333

posted @ 2022-12-16 18:59  啊原来是这样呀  阅读(12)  评论(0编辑  收藏  举报