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.

asked 14 Sep '10, 01:17

1337c0d3r's gravatar image

1337c0d3r ♦♦
456332137
accept rate: 0%


First, you must understand the difference between Binary Tree and Binary Search Tree (BST). Binary tree is a tree data structure in which each node has at most two child nodes. A binary search tree (BST) is based on binary tree, but with the following additional properties:

  • 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.

This question is a very good interview question, because it really tests your understanding of the definition of BST. Most people will fall to this first trap, and gives the following algorithm:

Assume that the current node's value is k. Then for each node, check if the left node's value is less than k and the right node's value is greater than k. If all of the nodes satisfy this property, then it is a BST.

It sounds correct and convincing, but look at this counter example below: A sample tree which we name it as binary tree (1).

    10
   /  \
  5   15     -------- binary tree (1)
     /  \
    6    20

It's obvious that this is not a valid BST, since (6) could never be on the right of (10).

Based on BST's definition, we can then easily devise a brute-force solution:

Assume that the current node's value is k. Then for each node, check if all nodes of left subtree contain values that are less than k. Also check if all nodes of right subtree contain values that are greater than k. If all of the nodes satisfy this property, then it must be a BST.

Below is the brute force code (though inefficient, but works):

bool isSubTreeLessThan(BinaryTree *p, int val) {
    if (!p) return true;
    return (p->data < val &&
            isSubTreeLessThan(p->left, val) &&
            isSubTreeLessThan(p->right, val));
}

bool isSubTreeGreaterThan(BinaryTree *p, int val) {
    if (!p) return true;
    return (p->data > val &&
            isSubTreeGreaterThan(p->left, val) &&
            isSubTreeGreaterThan(p->right, val));
}

bool isBSTBruteForce(BinaryTree *p) {
    if (!p) return true;
    return isSubTreeLessThan(p->left, p->data) &&
    isSubTreeGreaterThan(p->right, p->data) &&
    isBSTBruteForce(p->left) &&
    isBSTBruteForce(p->right);
}

Solution:
Here is the much better solution. Instead of examining all nodes of both subtrees in each pass, we only need to examine two nodes in each pass.

Refer back to the binary tree (1) above. As we traverse down the tree from node (10) to right node (15), we know for sure that the right node's value fall between 10 and +INFINITY. Then, as we traverse further down from node (15) to left node (6), we know for sure that the left node's value fall between 10 and 15. And since (6) does not satisfy the above requirement, we can quickly determine it is not a valid BST. All we need to do is to pass down the low and high limits from node to node! Once we figure out this algorithm, it is easy to code.

bool isBSTHelper(BinaryTree *p, int low, int high) {
    if (!p) return true;
    if (low < p->data && p->data < high)
        return isBSTHelper(p->left, low, p->data) &&
    isBSTHelper(p->right, p->data, high);
    else
        return false;
}

bool isBST(BinaryTree *root) {
    // INT_MIN and INT_MAX are defined in C++'s <climits> library
    return isBSTHelper(root, INT_MIN, INT_MAX);
}

This algorithm runs in O(N) time, where N is the number of nodes of the binary tree. It also uses O(1) space (neglecting the stack space used by calling function recursively).

Alternative Solution:
Another solution is to do an in-order traversal of the binary tree, and verify that the previous value (can be passed into the recursive function as reference) is less than the current value. This works because when you do an in-order traversal on a BST, the elements must be strictly in increasing order. This method also runs in O(N) time and O(1) space.

bool isBSTInOrderHelper(BinaryTree *p, int& prev) {
    if (!p) return true;
    return (isBSTInOrderHelper(p->left, prev) &&
            (p->data > prev) && (prev = p->data) &&
            isBSTInOrderHelper(p->right, prev));
}

bool isBSTInOrder(BinaryTree *root) {
    int prev = INT_MIN;
    return isBSTInOrderHelper(root, prev);
}

EDIT: (Bug fix)
An id han6 pointed that the above code has a bug. When one of the node's value is 0, the function would return false straight away, even though it is a valid BST. Why?

Below is the corrected code:

bool isBSTInOrderHelper(BinaryTree *p, int& prev) {
    if (!p) return true;
    if (isBSTInOrderHelper(p->left, prev)) {
        if (p->data > prev) {
            prev = p->data;
            return isBSTInOrderHelper(p->right, prev);
        } else {
            return false;
        }
    }
    else {
        return false;
    }
}

Additional Exercise:
We know that the brute force solution is inefficient. But how does it compare to the better solutions? In other words, what is the run time complexity of the brute force solution? Try to estimate as best as you can, and then find the correct answer by proving it using Math. Does your estimate fares well with the correct answer? Why?

(Hint: The run time complexity for the brute force approach is NOT exponential.)

link

answered 14 Sep '10, 01:17

1337c0d3r's gravatar image

1337c0d3r ♦♦
456332137
accept rate: 0%

I have a question about the In Order approach. What if the most left leaf value equal Integer.MIN_VALUE?

(18 Jan, 09:29) etlds etlds's gravatar image

Tests if a tree meets the conditions to be a binary search tree (BST). Efficient BST helper -- Given a node, and min and max values, recurs down the tree to verify that it is a BST, and that all its nodes are within the min..max range. Works in O(n) time -- visits each node only once.

public boolean isBST() {

return( isBST(root, Integer.MIN_VALUE, Integer.MAX_VALUE) );

}

public boolean isBST( Node root, int min, int max ) {

if (root == null ) return true;
else {
    if ( ! (root.data > min && root.data < max ) )
        retrn false;

    bool lBST = isBST( root.left, min, root.data);
    if (!lBST) return false; // No need to proceed

    bool rBST = isBST( root.left, root.data+1, max);

    return (lBST && rBST) ;  // just return rBST
}

}

link

answered 20 Jan, 15:21

serena's gravatar image

serena
111
accept rate: 0%

public class Solution {
public class Pair {
    boolean valid;
    Integer retMin;
    Integer retMax;
    public Pair(boolean valid,Integer retMin, Integer retMax) {
        this.valid = valid;
        this.retMin = retMin;
        this.retMax = retMax;
    }
}
public Pair validHelper(TreeNode root, boolean isLeft) {
    if (root==null) return new Pair(true,null,null);
    if (root.left!=null) {
        if (root.left.val>=root.val) return new Pair(false,null,null);
    }
    if (root.right!=null) {
        if (root.right.val<=root.val) return new Pair(false,null,null);
    }
    Pair vLeft = validHelper(root.left,true);
    Pair vRight = validHelper(root.right,false);
    if (vLeft.valid && vRight.valid) {
        if (vLeft.retMax != null && vLeft.retMax >= root.val) return new Pair(false,null,null);
        if (vRight.retMin != null && vRight.retMin <= root.val) return new Pair(false,null,null);
        return new Pair(true,(vLeft.retMin!=null?vLeft.retMin:root.val),(vRight.retMax!=null?vRight.retMax:root.val));
    } else 
        return new Pair(false,null,null);
}
public boolean isValidBST(TreeNode root) {
    // Start typing your Java solution below
    // DO NOT write main() function
    return validHelper(root,true).valid;
}
}
link

answered 06 Feb, 09:10

jjlights's gravatar image

jjlights
102
accept rate: 0%

I use Integers for my bounds, where null means do not check this bound. I do this to correctly handle the case where a valid node has a value of Integer.MAX_VALUE or Integer.MIN_VALUE.

public boolean isValidBST(TreeNode root) {
    return isValidBST(root, null, null);
}

public boolean isValidBST(TreeNode current, Integer lower, Integer upper) {
    if (current == null) {
        return true;
    } else if (lower != null && lower >= current.val) {
        return false;
    } else if (upper != null && upper <= current.val) {
        return false;
    } else {
        return isValidBST(current.left, lower, current.val) && isValidBST(current.right, current.val, upper);
    }
}
link

answered 27 Feb, 16:33

skaugust's gravatar image

skaugust
213
accept rate: 0%

edited 27 Feb, 16:34

bool isBSTHelper(TreeNode* root, int l, int u)
{
    bool bLeft = true;
    if( root->left )
    {
        bLeft &= root->left->val < root->val;
        if( l < root->val )
            bLeft &= root->left->val > l;
        bLeft &= isBSTHelper(root->left, l < root->left->val ? l : root->left->val, u);
    }
    bool bRight = true;
    if( root->right )
    {
        bRight &= root->right->val > root->val;
        if( u > root->val )
            bRight &= root->right->val < u;
        bRight &= isBSTHelper(root->right, l, root->right->val > u ? root->right->val : u);
    }
    return bLeft && bRight;
}
bool isValidBST(TreeNode *root) {
    // Start typing your C/C++ solution below
    // DO NOT write int main() function
    if( root == NULL )
        return true;
    bool bLeft = true;
    if( root->left )
    {
        bLeft &= root->left->val < root->val;
        bLeft &= isBSTHelper(root->left, root->left->val, root->val);
    }
    bool bRight = true;
    if( root->right )
    {
        bRight &= root->right->val > root->val;
        bRight &= isBSTHelper(root->right, root->val, root->right->val);
    }
    return bLeft && bRight;

}
link

answered 03 Mar, 09:34

dmy13's gravatar image

dmy13
11
accept rate: 0%

bool isValidBST(TreeNode *root) {
    // Start typing your C/C++ solution below
    // DO NOT write int main() function
    if (!root)
        return true;
    return isValid(root, -1*INT_MAX, INT_MAX);
}

bool isValid(TreeNode *root, int min, int max) {

    if (!root)
        return true;

    if (root->val <= min || root->val >= max) 
        return false;
    if (root->left && root->left->val >= root->val)
        return false;
    if (root->right && root->right->val <= root->val)
        return false;

    bool ret = true;
    ret &= isValid(root->left, min, root->val);
    ret &= isValid(root->right, root->val, max);

}
link

answered 04 Mar, 00:06

Shengzhe%20Chen's gravatar image

Shengzhe Chen
423
accept rate: 4%

Use recursive method and return the minimum and maximum values of left/right subtrees. Then compare those min/max values with the value of the current root node.

bool checkBST(TreeNode *root, int &bmin, int &bmax) {
    bool isBST;
    int lmin, lmax, rmin, rmax;

    if (!root) {
        bmin = INT_MAX;
        bmax = INT_MIN;
        return true;
    }

    isBST = checkBST(root->left, lmin, lmax) && checkBST(root->right, rmin, rmax);
    bmin = min(root->val, min(lmin, rmin));
    bmax = max(root->val, max(lmax, rmax));

    return (isBST && root->val > lmax && root->val < rmin);
}

bool isValidBST(TreeNode *root) {
    // Start typing your C/C++ solution below
    // DO NOT write int main() function
    int min, max;

    return checkBST(root, min, max);
}
link

answered 20 Mar, 20:50

whitebluff's gravatar image

whitebluff
111
accept rate: 0%

bool isvalidBSTHelp(TreeNode *root, int lb, int ub){
    if (lb < root->val && root->val < ub) {  
        if (root->left && !isvalidBSTHelp(root->left, lb, root->val) ||
        root->right && !isvalidBSTHelp(root->right, root->val, ub)){
            return false;
        }
        return true;
    }
    else {
        return false;
    }

}
bool isValidBST(TreeNode *root) {
    // Start typing your C/C++ solution below
    // DO NOT write int main() function
    if (!root) return true;
    return isvalidBSTHelp(root, INT_MIN, INT_MAX);
}
link

answered 30 Mar, 13:49

cookid's gravatar image

cookid
113
accept rate: 0%

Your answer
toggle preview

Follow this question

By Email:

Once you sign in you will be able to subscribe for any updates here

By RSS:

Answers

Answers and Comments

Markdown Basics

  • *italic* or _italic_
  • **bold** or __bold__
  • Indent code by 4 spaces.
  • link:[text](http://url.com/ "Title")
  • image?![alt text](/path/img.jpg "Title")
  • numbered list: 1. Foo 2. Bar
  • to add a line break simply add two spaces to where you would like the new line to be.
  • basic HTML tags are also supported

Tags:

×132
×20

Asked: 14 Sep '10, 01:17

Seen: 509 times

Last updated: 30 Mar, 13:49