LeetCode/solutions/145. Binary Tree Postorder Traversal.md
2020-06-27 20:47:28 +08:00

108 lines
3.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# [145. Binary Tree Postorder Traversal](https://leetcode.com/problems/binary-tree-postorder-traversal/)
# 思路
二叉树的后序遍历。递归方式很简单,这里主要讨论非递归方式。
## 思路一
除了层序遍历,二叉树的前序、中序、后序遍历的非递归算法一般都是用栈。后序遍历中比较特殊的是每个节点会有两次出现在栈顶:
1. 第一次是当其左右子树都还没访问时,所以应该按序将其右、左子树入栈(注意不会将该结点出栈);
2. 第二次是当其左右子树都遍历完毕时,所以应该将其出栈并访问。
可见我们需要记录一下每个结点是否已经在栈顶出现过一次了可用hashset来记录。
## 思路二
思路一需要一个hashset来记录某个结点的左右子树是否已经访问完毕即之前是否在栈顶出现过空间复杂度比较大。
其实可以用一个指针pre达到上述目的用pre指向前一个遍历的节点栈顶元素分如下三种情况
1. 如果栈顶元素是叶子那么直接出栈并访问然后更新pre
2. 如果栈顶元素的左孩子或右孩子是pre说明左右子树都已经处理完毕那么应该将当前元素出栈并访问然后更新pre
3. 否则,说明左右子树还未访问,将左右孩子入栈。
需要说明的是pre的初始值原则上任意都可以但是其实不能为NULL否则如果某结点有一个空孩子那么就会满足上面的第2个条件这是不对的。
同理也不能初始化为树中其他结点以免错误判断上面的第2个条件初始为root是可以的
## 思路三、修改前序遍历
我们知道前序遍历是按照"根左右"的原则遍历的,而后序遍历则是按照"左右根"的遍历原则。那么我们可以稍加修改前序遍历的代码,使其按照"根右左"遍历,最后再将结果翻转就得到了"左右根"遍历结果。
# C++
## 思路一
``` C++
class Solution {
public:
vector<int> postorderTraversal(TreeNode* root) {
vector<int>res;
if(!root) return res;
stack<TreeNode *>stk{{root}};
set<TreeNode *>flag;
TreeNode *p = NULL;
while(!stk.empty()){
p = stk.top();
if(flag.find(p) == flag.end()){ // 第一次出现在栈顶
flag.insert(p);
if(p -> right) stk.push(p -> right);
if(p -> left) stk.push(p -> left);
}
else{ // 第二次出现在栈顶
res.push_back(p -> val);
stk.pop();
}
}
return res;
}
};
```
## 思路二
``` C++
class Solution {
public:
vector<int> postorderTraversal(TreeNode* root) {
vector<int>res;
if(!root) return res;
stack<TreeNode *>stk{{root}};
TreeNode *p = NULL, *pre = root; // pre不能为NULL!!
while(!stk.empty()){
p = stk.top();
if((!p -> left && !p -> right) || p -> left == pre || p -> right == pre){
res.push_back(p -> val);
stk.pop();
pre = p;
}
else{
if(p -> right) stk.push(p -> right);
if(p -> left) stk.push(p -> left);
}
}
return res;
}
};
```
## 思路三
``` C++
class Solution {
public:
vector<int> postorderTraversal(TreeNode* root) {
vector<int>res;
if(!root) return res;
stack<TreeNode *>stk{{root}};
TreeNode *p = NULL;
while(!stk.empty()){
p = stk.top(); stk.pop();
res.push_back(p -> val);
// 前序遍历这里是先右后左
if(p -> left) stk.push(p -> left);
if(p -> right) stk.push(p -> right);
}
reverse(res.begin(), res.end()); // 前序遍历无这句
return res;
}
};
```