package com.freetymekiyan.algorithms.level.medium;
import com.freetymekiyan.algorithms.utils.Utils.TreeNode;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
/**
* Given a binary tree, determine if it is a valid binary search tree (BST).
* <p>
* Assume a BST is defined as follows:
* <p>
* 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.
* Example 1:
* | 2
* | / \
* | 1 3
* Binary tree [2,1,3], return true.
* <p>
* Example 2:
* | 1
* | / \
* | 2 3
* Binary tree [1,2,3], return false.
* Company Tags: Amazon, Microsoft, Bloomberg, Facebook
* Tags: Tree, Depth-first Search
* Similar Problems: (M) Binary Tree Inorder Traversal
*/
public class ValidateBinarySearchTree {
TreeNode pred = null;
private ValidateBinarySearchTree v;
/**
* Recursive, in-order traversal.
* Base case:
* Check current root, if its null, return true.
* Recurrence relation:
* root must be larger than the largest in left subtree,
* smaller than the smallest in right subtree.
* Left subtree and right subtree mush also be BST.
* Implementation:
* Check left subtree, if its not a BST, return false.
* Use a pointer to remember the largest node in the left subtree.
* Compare with current node and update pointer.
* Check right subtree, if its not a BST, return false.
* Return true if all tests passed.
*/
public boolean isValidBST(TreeNode root) {
if (root == null) {
return true;
}
if (!isValidBST(root.left)) {
return false;
}
if (pred != null && pred.val >= root.val) {
return false;
}
pred = root;
if (!isValidBST(root.right)) {
return false;
}
return true;
}
/**
* Recursive.
* Build a helper function with range.
* Check whether root's val is in range.
* Then check left and right recursively.
* Will fail if input include Integer MAX and Integer MIN.
*/
public boolean isValidBSTB(TreeNode root) {
return isValidBSTB(root, Integer.MIN_VALUE, Integer.MAX_VALUE);
}
// add range of current value and do recursive check
private boolean isValidBSTB(TreeNode root, int min, int max) {
return root == null || root.val > min && root.val < max && isValidBSTB(root.left, min, root.val) && isValidBSTB(
root.right, root.val, max);
}
/**
* Recursive, in-order.
* Inorder traversal, generate a list.
* The list should be in increasing order.
*/
public boolean isValidBSTC(TreeNode root) {
if (root == null) {
return true;
}
List<Integer> result = new ArrayList<Integer>();
inOrderList(root, result);
for (int i = 0; i < result.size() - 1; i++) {
if (result.get(i) >= result.get(i + 1)) {
return false;
}
}
return true;
}
private void inOrderList(TreeNode root, List<Integer> res) {
if (root == null) {
return;
}
inOrderList(root.left, res);
res.add(root.val);
inOrderList(root.right, res);
}
/**
* Recursive, pre-order.
* Check if root.val is bigger than value of rightmost node in left subtree.
* And smaller than value of leftmost node in right subtree.
*/
public boolean isValidBSTD(TreeNode root) {
if (root == null) {
return true;
}
TreeNode temp = null;
if (root.left != null) {
temp = root.left;
while (temp.right != null) {
temp = temp.right;
}
if (temp.val >= root.val) {
return false;
}
}
if (root.right != null) {
temp = root.right;
while (temp.left != null) {
temp = temp.left;
}
if (temp.val <= root.val) {
return false;
}
}
return isValidBST(root.left) && isValidBST(root.right);
}
@Before
public void setUp() {
v = new ValidateBinarySearchTree();
}
@Test
public void testExamples() {
TreeNode r = new TreeNode(Integer.MAX_VALUE);
Assert.assertTrue(v.isValidBST(r));
// Assert.assertTrue(v.isValidBSTB(r));
Assert.assertTrue(v.isValidBSTC(r));
Assert.assertTrue(v.isValidBSTD(r));
}
@After
public void tearDown() {
v = null;
}
}