Given a binary tree, return the postorder traversal of its nodes' values.
Example:
Input:[1,null,2,3]
1 \ 2 / 3 Output:[3,2,1]
Follow up: Recursive solution is trivial, could you do it iteratively?
The core challenge of this problem is to traverse a binary tree in postorder (left-right-root) and return the values of the nodes in the correct order. Postorder traversal is significant in various applications such as expression tree evaluations, file system traversals, and more.
Potential pitfalls include misunderstanding the traversal order and handling null nodes incorrectly.
To solve this problem, we can consider both recursive and iterative approaches:
The recursive approach is straightforward. We define a function that recursively visits the left subtree, then the right subtree, and finally processes the root node.
The iterative approach is more complex but can be achieved using a stack. We use two stacks to simulate the postorder traversal. The first stack is used to traverse the tree, and the second stack is used to store the nodes in postorder.
// 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:
void postorderTraversalHelper(TreeNode* node, vector<int>& result) {
if (node == NULL) return;
// Traverse left subtree
postorderTraversalHelper(node->left, result);
// Traverse right subtree
postorderTraversalHelper(node->right, result);
// Visit the root node
result.push_back(node->val);
}
vector<int> postorderTraversal(TreeNode* root) {
vector<int> result;
postorderTraversalHelper(root, result);
return result;
}
};
#include <vector>
#include <stack>
using namespace std;
// 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> result;
if (root == NULL) return result;
stack<TreeNode*> s1, s2;
s1.push(root);
while (!s1.empty()) {
TreeNode* node = s1.top();
s1.pop();
s2.push(node);
if (node->left) s1.push(node->left);
if (node->right) s1.push(node->right);
}
while (!s2.empty()) {
result.push_back(s2.top()->val);
s2.pop();
}
return result;
}
};
Both the recursive and iterative solutions have a time complexity of O(n), where n is the number of nodes in the tree. This is because each node is visited exactly once.
The space complexity for the recursive solution is O(h), where h is the height of the tree, due to the call stack. For the iterative solution, the space complexity is O(n) due to the use of two stacks.
Potential edge cases include:
Each algorithm handles these cases by checking if the node is null and proceeding accordingly.
To test the solution comprehensively, consider the following test cases:
[]
[1]
[1,2,3,4,5,6,7]
[1,null,2,null,3]
Use a testing framework like Google Test for C++ to automate the testing process.
When approaching tree traversal problems, it is helpful to:
To improve problem-solving skills, solve similar problems and study various tree traversal algorithms.
Postorder tree traversal is a fundamental problem in computer science with various applications. Understanding both recursive and iterative solutions is crucial for tackling more complex tree-related problems. Practice and exploration of different approaches will enhance your problem-solving skills.
For further reading and practice, consider the following resources: