11## 题目地址   
22https://leetcode-cn.com/problems/invert-binary-tree/ 
33
4- ##  思路    
4+ #  226.翻转二叉树  
55
6- ### 递归法  
7- 写递归算法的时候,要想一想是采用前中后序哪种遍历方式
8- o
9- 如果对递归还不熟,可以看这里[ 彻底吃透二叉树的前中后序递归法和迭代法!!] ( https://leetcode-cn.com/problems/binary-tree-inorder-traversal/solution/che-di-chi-tou-er-cha-shu-de-qian-zhong-hou-xu-d-2/ ) 
6+ 翻转一棵二叉树。
107
11- 我们先看看递归算法,对于二叉树的递归方式有三种前中后序,先来看看前序遍历。 
8+ < img   src = ' ../pics/226.翻转二叉树.png '   width = 600 > </ img ></ div > 
129
13- 通过动画来看一下翻转的过程: 
10+ 这道题目背后有一个让程序员心酸的故事,听说 Homebrew的作者Max Howell,就是因为没在白板上写出翻转二叉树,最后被Google拒绝了。(真假不做判断,权当一个乐子哈)  
1411
15- < video   src = ' ../video/翻转二叉树.mp4 '   controls = ' controls '   width = ' 640 '   height = ' 320 '   autoplay = ' autoplay ' > Your browser does not support the video tag.</ video ></ div > 
12+ #  题外话   
1613
17- 递归三部曲:
14+ 这道题目是非常经典的题目,也是比较简单的题目(至少一看就会)。
15+ 
16+ 但正是因为这道题太简单,一看就会,一些同学都没有抓住起本质,稀里糊涂的就把这道题目过了。
17+ 
18+ 如果做过这道题的同学也建议认真看完,相信一定有所收获!
19+ 
20+ # 思路   
21+ 
22+ 我们之前介绍的都是各种方式遍历二叉树,这次要翻转了,感觉还是有点懵逼。
23+ 
24+ 这得怎么翻转呢? 
25+ 
26+ 如果要从整个树来看,翻转还真的挺复杂,整个树以中间分割线进行翻转,如图:
27+ 
28+ <img  src =' ../pics/226.翻转二叉树1.png '  width =600 > </img ></div >
29+ 
30+ 可以发现想要翻转它,其实就把每一个节点的左右孩子交换一下就可以了。
31+ 
32+ 关键在于遍历顺序,前中后序应该选哪一种遍历顺序? (一些同学这道题都过了,但是不知道自己用的是什么顺序)
33+ 
34+ 遍历的过程中去翻转每一个节点的左右孩子就可以达到整体翻转的效果。
35+ 
36+ ** 注意只要把每一个节点的左右孩子翻转一下,就可以达到整体翻转的效果** 
37+ 
38+ ** 这道题目使用前序遍历和后序遍历都可以,唯独中序遍历不行,因为中序遍历会把某些节点的左右孩子翻转了两次!建议拿纸画一画,就理解了** 
39+ 
40+ 那么层序遍历可以不可以呢?** 依然可以的!只要把每一个节点的左右孩子翻转一下的遍历方式都是可以的!** 
41+ 
42+ ## 递归法  
43+ 
44+ 对于二叉树的递归法的前中后序遍历,已经在[ 二叉树:前中后序递归遍历] ( https://mp.weixin.qq.com/s/PwVIfxDlT3kRgMASWAMGhA ) 详细讲解了。
45+ 
46+ 我们下文以前序遍历为例,通过动画来看一下翻转的过程:
47+ 
48+ <img  src =' ../video/翻转二叉树.gif '  width =600 > </img ></div >
49+ 
50+ 我们来看一下递归三部曲:
1851
19521 .  确定递归函数的参数和返回值
2053
21- 参数就是要传入节点的指针,不需要其他参数了,返回值的话其实也不需要,但是题目中给出的要返回root节点的指针,可以直接使用题目定义好的函数,所以就返回一个指针。
54+ 参数就是要传入节点的指针,不需要其他参数了,通常此时定下来主要参数,如果在写递归的逻辑中发现还需要其他参数的时候,随时补充。
55+ 
56+ 返回值的话其实也不需要,但是题目中给出的要返回root节点的指针,可以直接使用题目定义好的函数,所以就函数的返回类型为` TreeNode* ` 。
2257
2358``` 
2459TreeNode* invertTree(TreeNode* root) 
@@ -34,7 +69,7 @@ if (root == NULL) return root;
3469
35703 .  确定单层递归的逻辑
3671
37- 因为是先序遍历 ,所以先进行交换左右孩子节点,然后反转左子树,反转右子树。
72+ 因为是先前序遍历 ,所以先进行交换左右孩子节点,然后反转左子树,反转右子树。
3873
3974``` 
4075swap(root->left, root->right); 
@@ -49,34 +84,21 @@ class Solution {
4984public: 
5085 TreeNode* invertTree(TreeNode* root) { 
5186 if (root == NULL) return root; 
52-  swap(root->left, root->right); 
53-  invertTree(root->left); 
54-  invertTree(root->right); 
87+  swap(root->left, root->right); // 中  
88+  invertTree(root->left); // 左  
89+  invertTree(root->right); // 右  
5590 return root; 
5691 } 
5792}; 
5893``` 
5994
60- ###  迭代法  
95+ ## 迭代法  
6196
62- [ leetcode-master ] ( https://github.com/youngyangyang04/leetcode-master )  中给出了 前中后序迭代法统一的模板,使用前序遍历,只需要改动一行就可以了,代码在下面已经给出。 
97+ ###  深度优先遍历 
6398
64- ##  C++代码 
99+ [ 二叉树:听说递归能做的,栈也能做! ] ( https://mp.weixin.qq.com/s/c_zCrGHIVlBjUH_hJtghCg ) 中给出了前中后序迭代方式的写法,所以本地可以很轻松的切出如下迭代法的代码: 
65100
66- ### 递归(前序遍历)  
67- ``` 
68- class Solution { 
69- public: 
70-  TreeNode* invertTree(TreeNode* root) { 
71-  if (root == NULL) return root; 
72-  swap(root->left, root->right); 
73-  invertTree(root->left); 
74-  invertTree(root->right); 
75-  return root; 
76-  } 
77- }; 
78- ``` 
79- ### 迭代法(前序遍历)  
101+ C++代码迭代法(前序遍历)
80102
81103``` 
82104class Solution { 
@@ -86,20 +108,22 @@ public:
86108 stack<TreeNode*> st; 
87109 st.push(root); 
88110 while(!st.empty()) { 
89-  TreeNode* node = st.top(); 
111+  TreeNode* node = st.top(); // 中  
90112 st.pop(); 
91-  swap(node->left, node->right); 
92-  if(node->left ) st.push(node->left);  
93-  if(node->right ) st.push(node->right);  
113+  swap(node->left, node->right);   
114+  if(node->right ) st.push(node->right); // 右  
115+  if(node->left ) st.push(node->left); // 左  
94116 } 
95117 return root; 
96118 } 
97119}; 
98120``` 
121+ 如果这个代码看不懂的话可以在回顾一下[ 二叉树:听说递归能做的,栈也能做!] ( https://mp.weixin.qq.com/s/c_zCrGHIVlBjUH_hJtghCg ) 。
122+ 
99123
100- ###  迭代法(前序遍历)(模板) 
124+ 我们在 [ 二叉树:前中后序迭代方式的统一写法 ] ( https://mp.weixin.qq.com/s/WKg0Ty1_3SZkztpHubZPRg ) 中介绍了统一的写法,所以,本题也只需将文中的代码少做修改便可。 
101125
102- 模板地址: [ leetcode-master ] ( https://github.com/youngyangyang04/leetcode-master ) 
126+ C++代码如下迭代法(前序遍历) 
103127
104128``` 
105129class Solution { 
@@ -111,9 +135,9 @@ public:
111135 TreeNode* node = st.top(); 
112136 if (node != NULL) { 
113137 st.pop(); 
114-  if (node->right) st.push(node->right); // 添加右节点  
115-  if (node->left) st.push(node->left); // 添加左节点  
116-  st.push(node); // 添加中节点  
138+  if (node->right) st.push(node->right); // 右  
139+  if (node->left) st.push(node->left); // 左  
140+  st.push(node); // 中  
117141 st.push(NULL); 
118142 } else { 
119143 st.pop(); 
@@ -126,4 +150,45 @@ public:
126150 } 
127151}; 
128152``` 
153+ 
154+ 如果上面这个代码看不懂,回顾一下文章[ 二叉树:前中后序迭代方式的统一写法] ( https://mp.weixin.qq.com/s/WKg0Ty1_3SZkztpHubZPRg ) 。
155+ 
156+ ### 广度优先遍历  
157+ 
158+ 也就是层序遍历,层数遍历也是可以翻转这棵树的,因为层序遍历也可以把每个节点的左右孩子都翻转一遍,代码如下:
159+ 
160+ ``` 
161+ class Solution { 
162+ public: 
163+  TreeNode* invertTree(TreeNode* root) { 
164+  queue<TreeNode*> que; 
165+  if (root != NULL) que.push(root); 
166+  while (!que.empty()) { 
167+  int size = que.size(); 
168+  for (int i = 0; i < size; i++) { 
169+  TreeNode* node = que.front(); 
170+  que.pop(); 
171+  swap(node->left, node->right); // 节点处理 
172+  if (node->left) que.push(node->left); 
173+  if (node->right) que.push(node->right); 
174+  } 
175+  } 
176+  return root; 
177+  } 
178+ }; 
179+ ``` 
180+ 如果对以上代码不理解,或者不清楚二叉树的层序遍历,可以看这篇[ 二叉树:层序遍历登场!] ( https://mp.weixin.qq.com/s/Gb3BjakIKGNpup2jYtTzog ) 
181+ 
182+ # 总结   
183+ 
184+ 针对二叉树的问题,解题之前一定要想清楚究竟是前中后序遍历,还是层序遍历。
185+ 
186+ ** 二叉树解题的大忌就是自己稀里糊涂的过了(因为这道题相对简单),但是也不知道自己是怎么遍历的。** 
187+ 
188+ 这也是造成了二叉树的题目“一看就会,一写就废”的原因。
189+ 
190+ ** 针对翻转二叉树,我给出了一种递归,三种迭代(两种模拟深度优先遍历,一种层序遍历)的写法,都是之前我们讲过的写法,融汇贯通一下而已。** 
191+ 
192+ 大家一定也有自己的解法,但一定要成方法论,这样才能通用,才能举一反三!
193+ 
129194>  更多算法干货文章持续更新,可以微信搜索「代码随想录」第一时间围观,关注后,回复「Java」「C++」 「python」「简历模板」「数据结构与算法」等等,就可以获得我多年整理的学习资料。
0 commit comments