You are given the root of a binary tree, return the postorder traversal of its nodes' values.
Example 1:
Input: root = [1,2,3,4,5,6,7]
Output: [4,5,2,6,7,3,1]Example 2:
Input: root = [1,2,3,null,4,5,null]
Output: [4,2,5,3,1]Example 3:
Input: root = []
Output: []Constraints:
0 <= number of nodes in the tree <= 100-100 <= Node.val <= 100Follow up: Recursive solution is trivial, could you do it iteratively?
Before attempting this problem, you should be comfortable with:
Postorder traversal visits nodes in the order: left subtree, right subtree, current node. This is useful when we need to process children before their parent, such as when deleting nodes or evaluating expression trees. Recursion naturally handles this by processing both subtrees before adding the current node's value.
node as input.node is null, return immediately (base case).# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def postorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
res = []
def postorder(node):
if not node:
return
postorder(node.left)
postorder(node.right)
res.append(node.val)
postorder(root)
return resWe use a stack with a visited flag to track whether we've already processed a node's children. When we first encounter a node, we push it back with a visited flag set to true, then push its children. On the second visit (when the flag is true), we know both children have been processed, so we add the node's value to the result.
false visited flag.visited flag.null, continue.visited is true, add the node's value to the result.visited set to true, then push the right child (visited false), then the left child (visited false).# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def postorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
stack = [root]
visit = [False]
res = []
while stack:
cur, v = stack.pop(), visit.pop()
if cur:
if v:
res.append(cur.val)
else:
stack.append(cur)
visit.append(True)
stack.append(cur.right)
visit.append(False)
stack.append(cur.left)
visit.append(False)
return resPostorder is the reverse of a modified preorder traversal. If we traverse in the order: current, right, left (instead of current, left, right), and then reverse the result, we get the postorder sequence. This avoids the complexity of tracking visited nodes.
null or the stack is not empty:null, add its value to the result, push it onto the stack, and move to the right child.# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def postorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
res = []
stack = []
cur = root
while cur or stack:
if cur:
res.append(cur.val)
stack.append(cur)
cur = cur.right
else:
cur = stack.pop()
cur = cur.left
res.reverse()
return resSimilar to the iterative approach that reverses a modified preorder, Morris Traversal for postorder works by performing a reverse preorder traversal (current, right, left) without using extra space for a stack. We use temporary thread links from the leftmost node of the right subtree back to the current node. After the traversal, we reverse the result.
null:null, add the current value to the result, set the left pointer to the current node (create thread), and move to the right child.# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def postorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
res = []
cur = root
while cur:
if not cur.right:
res.append(cur.val)
cur = cur.left
else:
prev = cur.right
while prev.left and prev.left != cur:
prev = prev.left
if not prev.left:
res.append(cur.val)
prev.left = cur
cur = cur.right
else:
prev.left = None
cur = cur.left
res.reverse()
return resPostorder requires visiting children before the current node. Adding the value before recursive calls produces preorder traversal instead.
# Wrong: this is preorder, not postorder
res.append(node.val)
postorder(node.left)
postorder(node.right)In the iterative approach using reversal, you must traverse current -> right -> left, then reverse. Traversing current -> left -> right and reversing gives incorrect results.