Your solution:
seems legit :)
One thing I'd suggest here is to use ArrayDeque instead of Stack
Another possible solution:
Basically, for every subtree we have constrain, that every node in it should be in range (X, Y).
For root this range will be (-inf; +inf) - in other words, there could be any value in root.
For root's left subtree range will be (-inf, value-in-root), for right - (value-in-root, +inf).
Last thing - on each iteration we should check, that value in node is within this range, like so:
public boolean doInOrderTraversal(TreeNode root, int min, int max) {
if (root == null) {
return true;
}
if (root.val <= min || root.val >= max) {
return false;
}
return doInOrderTraversal(root.left, min, root.val) && doInOrderTraversal(root.right, rotroot.val, max);
}