[LintCode] Validate Binary Search Tree
Given a binary tree, determine if it is a valid binary search tree (BST).
Assume a BST is defined as follows:
- The left subtree of a node contains only nodes with keys less than the node‘s key.
- The right subtree of a node contains only nodes with keys greater than the node‘s key.
- Both the left and right subtrees must also be binary search trees.
- A single node tree is a BST
An example:
2
/ 1 4
/ 3 5
The above binary tree is serialized as {2,1,4,#,#,3,5}
(in level order).
Solution 1. In-Order Traversal, O(n) runtime, O(n) space
If a binary tree is a BST, then in order traversal returns a list of nodes whose values are strictly increasing.
1 /** 2 * Definition of TreeNode: 3 * public class TreeNode { 4 * public int val; 5 * public TreeNode left, right; 6 * public TreeNode(int val) { 7 * this.val = val; 8 * this.left = this.right = null; 9 * } 10 * } 11 */ 12 public class Solution { 13 /**14 * @param root: The root of binary tree. 15 * @return: True if the binary tree is BST, or false 16 */ 17 public boolean isValidBST(TreeNode root) { 18 ArrayList<Integer> inOrderList = new ArrayList<Integer>(); 19 isValidBSTHelper(root, inOrderList); 20 boolean result = true; 21 if(inOrderList.size() > 1) 22 { 23 for(int i = 1; i < inOrderList.size(); i++) 24 { 25 if(inOrderList.get(i - 1) >= inOrderList.get(i)) 26 { 27 result = false; 28 break; 29 } 30 } 31 } 32 return result; 33 } 34 private void isValidBSTHelper(TreeNode root, ArrayList<Integer> inOrderList) 35 { 36 if(root != null) 37 { 38 isValidBSTHelper(root.left, inOrderList); 39 inOrderList.add(root.val); 40 isValidBSTHelper(root.right, inOrderList); 41 } 42 } 43 }
Solution 2. Optimization upon solution 1, still using recursion.
The run time of solution 1 is already BCR, so we consider if space usage can be optimized.
Since we only need to check if the given binary tree is a BST or not, we don‘t need to return
all the locations where BST property is violated. This means we can introduce another parameter
to the in order traversal helper function that keeps the "just visited" tree node. Each time we visit
a new node, compare its value with the value of "just visited" node. If not bigger, we know the
given binary tree is not a BST, exit and return false.
This optimization saves us from using a O(n) size arraylist. But the worst case recursion space is
still O(n).
1 public class Solution { 2 private TreeNode prevNode = null; 3 public boolean isValidBST(TreeNode root) { 4 return helper(root); 5 } 6 private boolean helper(TreeNode currNode){ 7 if(currNode == null){ 8 return true; 9 } 10 if(!helper(currNode.left)){ 11 return false; 12 } 13 if(prevNode != null && prevNode.val >= currNode.val){ 14 return false; 15 } 16 prevNode = currNode; 17 if(!helper(currNode.right)){ 18 return false; 19 } 20 return true; 21 } 22 }
Solution 3. Iterative implementation of solution 2.
1 public class Solution { 2 public boolean isValidBST(TreeNode root) { 3 TreeNode prevNode = null, currNode = root; 4 Stack<TreeNode> stack = new Stack<TreeNode>(); 5 boolean finished = false; 6 while(!finished){ 7 while(currNode != null){ 8 stack.push(currNode); 9 currNode = currNode.left; 10 } 11 if(stack.isEmpty()){ 12 finished = true; 13 } 14 else{ 15 currNode = stack.pop(); 16 if(prevNode != null && prevNode.val >= currNode.val){ 17 return false; 18 } 19 prevNode = currNode; 20 currNode = currNode.right; 21 } 22 } 23 return true; 24 } 25 }
Solution 4. Divide and Conquer, O(n) runtime and O(1) space, if not considering recursion space usage.
Key idea here is that to maintain a BST property for a given node, the following 2 properties must be true
1. Its left subtree and right subtree must be BST;
2. Its value must be bigger than the max value of its left subtree and smaller than the min value of its right subtree.
1 class ResultType { 2 boolean is_bst; 3 int maxValue, minValue; 4 5 ResultType(boolean is_bst, int maxValue, int minValue) { 6 this.is_bst = is_bst; 7 this.maxValue = maxValue; 8 this.minValue = minValue; 9 } 10 } 11 12 public class Solution { 13 public boolean isValidBST(TreeNode root) { 14 ResultType r = validateHelper(root); 15 return r.is_bst; 16 } 17 18 private ResultType validateHelper(TreeNode root) { 19 if (root == null) { 20 return new ResultType(true, Integer.MIN_VALUE, Integer.MAX_VALUE); 21 } 22 23 ResultType left = validateHelper(root.left); 24 ResultType right = validateHelper(root.right); 25 26 if (!left.is_bst || !right.is_bst) { 27 // if is_bst is false then minValue and maxValue are useless 28 return new ResultType(false, 0, 0); 29 } 30 31 if (root.left != null && left.maxValue >= root.val || 32 root.right != null && right.minValue <= root.val) { 33 return new ResultType(false, 0, 0); 34 } 35 36 return new ResultType(true, 37 Math.max(root.val, right.maxValue), 38 Math.min(root.val, left.minValue)); 39 } 40 }
Related Problems
Balanced Binary Tree
Inorder Successor in Binary Search Tree
Binary Tree Inorder Traversal
Binary Tree Preorder Traversal
Binary Tree Postorder Traversal
[LintCode] Validate Binary Search Tree