by Xin Hong
After revisiting the inorder traversal (using stack), some if-statements make more sense to me… Here’s a wrong version and a corrected version.
What’s wrong with the following code? You can paste it in leetcode no.94, it won’t work because of timeout.
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
// (left), (root), (right)
var stack = new ArrayDeque<TreeNode>();
var res = new ArrayList<Integer>();
while (!stack.isEmpty() || root != null) {
while (root != null) {
stack.push(root);
root = root.left;
}
if (!stack.isEmpty()) {
root = stack.pop();
}
if (root != null) {
res.add(root.val);
if (root.right != null) {
root = root.right;
}
}
}
return res;
}
}
Take the following example: 1 3 2
The problem is when root has no left child, we should let root = root.right
even though root.right
might be null
.
Otherwise,
root
will not be null
and therefore the subroutine will never end.root
is not null
, we add it in the stack at the beginning, then we pop the stack, retrieving the same node, and it’s going on and on…Further more, it seems logical to add if (!stack.isEmpty())
before we pop the stack, but come to think of it, we don’t actually need this. While entering the subroutine, the conditions ensure that:
if
statement. However, even when stack is empty, node is not null. Therefore, it will be pushed to the stack, which results a non-empty stack. Therefore, either way, the stack is not empty.If the stack is not empty, we will surely get a non-null node after root = stack.pop()
, thus even the if (root != null)
is excessive.
The code can be corrected and simplified as:
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
// left, root, right
var stack = new ArrayDeque<TreeNode>();
var res = new ArrayList<Integer>();
while (!stack.isEmpty() || root != null) {
while (root != null) {
stack.push(root);
root = root.left;
}
// At this point, stack can't be empty.
root = stack.pop();
res.add(root.val);
// if root.right == null, it's fine.
root = root.right;
}
return res;
}
}