102. Binary Tree Postorder Traversal
Given a binary tree, return thepostordertraversal of its nodes' values.
For example:
Given binary tree{1,#,2,3}
,
1
\
2
/
3
return[3,2,1]
.
Note:Recursive solution is trivial, could you do it iteratively?
Trivial Solution:
- Recursion Call
- Reverse the Binary Tree pre order traversal output
Thoughts:
Using stack: pshizhsysu generalized the tree traversal idea: O(n) in time and O(n) in space
- For postorder traversal, we visit a node when popping it. last_pop represents the node which is popped the last time. For the top node in stack, it has three choices, pushing its left child in stack, or pushing its right child in stack, or being popped. If last_pop != top->left, meaning that its left tree has not been pushed in stack, then we push its left child. If last_pop == top->left, we push its right child. Otherwise, we pop the top node.
- In contrast, for pre order traversal, we visit a node when pushing it in stack. For in order traversal, we visit a node when pushing its right child in stack.
Always use a lastNode, the (last node added to the answer), to keep track whether cur-> right is the same as that (if it is then, we need to visit the CurNode, if it is not, then we need to first visit cur->right)
Morris Traversal (Adopted from jianchaolifighter's Solution ) : O(n) in time and O(1) in space
Code 1:
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
vector<int> postorderTraversal(TreeNode* root) {
vector<int>answer;
if (root == 0)
return answer;
stack<TreeNode*> s;
s.push(root);
TreeNode* last_pop = root;
while (!s.empty())
{
TreeNode* top = s.top();
if (top->left && top->left != last_pop && top->right != last_pop) // push_left
{
s.push(top->left);
}
else if (top->right && top->right != last_pop && (!top->left || top->left == last_pop)) // push_right
{
s.push(top->right);
}
else // pop
{
s.pop();
last_pop = top;
// cout << top->val << ' '; // visit top
answer.push_back(top -> val);
}
}
return answer;
}
};
Code 1 by jianchaolifighter's solution:
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
vector<int> postorderTraversal(TreeNode* root) {
vector<int> answer;
stack<TreeNode *> toVisit;
TreeNode * nodeToLeft = root;
TreeNode * lastNode = NULL; // You must assign NULL here as it will have some wired problems of not passing the
// case of "[1,null,2]"( I guess memory leak?)
while(nodeToLeft || !toVisit.empty()){
if(nodeToLeft){
toVisit.push(nodeToLeft);
nodeToLeft = nodeToLeft -> left;
}
else{
TreeNode * topNode = toVisit.top();
if(topNode -> right && lastNode != topNode -> right)
nodeToLeft = topNode -> right;
else {
answer.push_back(topNode->val);
lastNode = topNode;
toVisit.pop();
}
}
}
return answer;
}
};
Code 2: Morris Traversal (hard):
- Visit left subtree find the right the rightmost tree, add a cycle to the current node - left subtree - right most point
- Iteratively creating cycles to the left (left) , until we detect a cycle, process the answer for the left subtree using three pointers, then move to the right subtree root, repeat 2 (right).
- right subtree root and current node are included when cycle between right subtree - root, current node - and parent is detected ( reason why to add a dummy node as the root)
class Solution{
public:
void reverseNodes(TreeNode* start, TreeNode* end) {
// if (start == end) return;
TreeNode* slow = start;
TreeNode* fast = start -> right;
TreeNode* fast_next;
while (slow != end) {
fast_next = fast-> right;
// changing right
fast -> right = slow;
// increment
slow = fast;
fast = fast_next;
}
}
void reverseAddNodes(TreeNode* start, TreeNode* end, vector<int>& nodes) {
reverseNodes(start, end);
TreeNode* node = end;
while (true) {
nodes.push_back(node -> val);
if (node == start) break;
node = node -> right;
}
reverseNodes(end, start);
}
vector<int> postorderTraversal(TreeNode* root) {
vector<int> nodes;
TreeNode* dump = new TreeNode (0);
dump -> left = root;
TreeNode* curNode = dump;
while (curNode) {
if (curNode -> left) {
TreeNode* predecessor = curNode -> left;
while (predecessor -> right && predecessor -> right != curNode)
predecessor = predecessor -> right;
if (!(predecessor -> right)) {
// add right path
predecessor -> right = curNode;
curNode = curNode -> left;
}
else {
// find a cycle, add left subtree
reverseAddNodes(curNode -> left, predecessor, nodes);
// prune cycle path, finish left subtree, switch to the right
predecessor -> right = NULL;
curNode = curNode -> right;
}
}
else curNode = curNode -> right;
}
return nodes;
}
};
Code 2 : Better Morris Traversal from Annie Kim's Blog