69

I read on here of an exercise in interviews known as validating a binary search tree.

How exactly does this work? What would one be looking for in validating a binary search tree? I have written a basic search tree, but never heard of this concept.

Bernhard Barker
  • 54,589
  • 14
  • 104
  • 138
GurdeepS
  • 65,107
  • 109
  • 251
  • 387
  • 31
    Use inorder traversal, and check if each element is greater than the previous element. – dalle Mar 30 '10 at 08:16

33 Answers33

117

Actually that is the mistake everybody does in an interview.

Leftchild must be checked against (minLimitof node,node.value)

Rightchild must be checked against (node.value,MaxLimit of node)

IsValidBST(root,-infinity,infinity);

bool IsValidBST(BinaryNode node, int MIN, int MAX) 
{
     if(node == null)
         return true;
     if(node.element > MIN 
         && node.element < MAX
         && IsValidBST(node.left,MIN,node.element)
         && IsValidBST(node.right,node.element,MAX))
         return true;
     else 
         return false;
}

Another solution (if space is not a constraint): Do an inorder traversal of the tree and store the node values in an array. If the array is in sorted order, its a valid BST otherwise not.

adl
  • 15,627
  • 6
  • 51
  • 65
g0na
  • 1,179
  • 1
  • 7
  • 3
  • 36
    "Another solution(if space is not a constraint) Do an inorder traversal of the tree and store the node values in an array. If the array is in sorted order, its a valid BST otherwise not."... Well you don't need _space_ or an array to do that. If you can do the traversal in the first place, and the array that you would create should be sorted, then each element that you visit during the traversal must be greater (or, in the limit case, equal) to the previous one, right? – Daniel Daranas Apr 17 '09 at 10:33
  • Yes. I agree with that. but still we need one global variable to assign and access the previous value in the recursive calls. and its better than my previous example passing (MIN,MAX) on each call and eat up space on stack. Thanks – g0na Apr 17 '09 at 10:50
  • Your algorithm is wrong... as if you have a tree with one root of value: 2 and one right child with value: 2, you will say it isn't a BST, when in fact it is. – Yarneo Sep 20 '12 at 14:55
  • 6
    @Yarneo A valid BST contains no duplicate nodes so I believe this algorithm is correct: http://en.wikipedia.org/wiki/Binary_search_tree – user784637 Jan 20 '13 at 23:35
  • @DanielDaranas can you tell me the runtime of this algorithm? – Prince Jan 17 '14 at 20:36
  • 3
    It won't pass the leetcode new online test. Change the int MIN/MAX to BinaryNode null then assign node to compare will help. – Wangsu Nov 25 '14 at 13:46
  • This code just works. It's simple, short, concise. I don't understand all of these remarks. – Enrico Giurin Feb 27 '17 at 20:26
19

"Validating" a binary search tree means that you check that it does indeed have all smaller items on the left and large items on the right. Essentially, it's a check to see if a binary tree is a binary search tree.

Kushal
  • 8,100
  • 9
  • 63
  • 82
wj32
  • 8,053
  • 3
  • 28
  • 37
  • 3
    I'm surprised that on a question that asks "What would one be looking for in validating a binary search tree?", the only answer that answers the question asked (this one) has so few votes, while answers that give code without even defining the problem have so many. – ShreevatsaR Oct 30 '18 at 23:10
16

The best solution I found is O(n) and it uses no extra space. It is similar to inorder traversal but instead of storing it to array and then checking whether it is sorted we can take a static variable and check while inorder traversing whether array is sorted.

static struct node *prev = NULL;

bool isBST(struct node* root)
{
    // traverse the tree in inorder fashion and keep track of prev node
    if (root)
    {
        if (!isBST(root->left))
          return false;

        // Allows only distinct valued nodes
        if (prev != NULL && root->data <= prev->data)
          return false;

        prev = root;

        return isBST(root->right);
    }

    return true;
}
Aayush Bahuguna
  • 161
  • 1
  • 4
  • Thanks for sharing this. Question: if I am not mistaken your algorithm actually takes O(n) space because of the call stack due to recursivity. Am I missing something? Nevertheless, it's very simple! – Andrew Feb 08 '17 at 13:32
  • Actually, the space complexity of your algorithm may be O(log n) for a balanced tree [as mentioned here](http://stackoverflow.com/questions/21546611/space-complexity-of-validation-of-a-binary-search-tree/21546734#21546734). – Andrew Feb 08 '17 at 13:43
  • I tried modifying this without using static variable, but could not! What do you think ? Thanks – Pranav Nandan Jun 02 '17 at 17:29
  • `uses no extra space` but for recursive calls. – greybeard Jul 01 '17 at 18:26
  • @PranavNandan: `tried [without] static variable, but [couldn't!?]` you need to specify a language to indicate the mechanisms available. With Java, an [atomic Number](http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/atomic/package-summary.html#package.description) parameter would seem an option for most primitive keys. In terms of this answer, `bool isBST(struct node const* root, struct node * prev)` should do, with a dummy node allocated (and specified …) in `bool isBST(struct node* root)`. – greybeard Jul 02 '17 at 03:08
  • 1
    Can we really do better than O(n)? We have to go to each node to validate if that subtree is a proper binary search tree or not. That makes it O(n) in worst case. – piepi Aug 19 '19 at 11:05
7

Iterative solution using inorder traversal.

bool is_bst(Node *root) {
  if (!root)
    return true;

  std::stack<Node*> stack;
  bool started = false;
  Node *node = root;
  int prev_val;

  while(true) {
    if (node) {
      stack.push(node);
      node = node->left();
      continue;
    }
    if (stack.empty())
      break;
    node = stack.top();
    stack.pop();

    /* beginning of bst check */
    if(!started) {
      prev_val = node->val();
      started = true;
    } else {
      if (prev_val > node->val())
        return false;
      prev_val = node->val();
    }
    /* end of bst check */

    node = node->right();
  }
  return true;
}
jae
  • 71
  • 1
  • 2
  • Good note to point out from your solution is that recursive solutions can sometimes be bad news on a production instance if you smash the stack – Grambot Jul 19 '12 at 13:58
5

Here is my solution in Clojure:

(defstruct BST :val :left :right)

(defn in-order [bst]
  (when-let [{:keys [val, left, right]} bst]
    (lazy-seq
      (concat (in-order left) (list val) (in-order right)))))

(defn is-strictly-sorted? [col]
  (every?
    (fn [[a b]] (< a  b))
    (partition 2 1 col)))

(defn is-valid-BST [bst]
  (is-strictly-sorted? (in-order bst)))
Dimagog
  • 1,785
  • 19
  • 14
4

Since the in-order traversal of a BST is a non-decrease sequence, we could use this property to judge whether a binary tree is BST or not. Using Morris traversal and maintaining the pre node, we could get a solution in O(n) time and O(1) space complexity. Here is my code

public boolean isValidBST(TreeNode root) {
    TreeNode pre = null, cur = root, tmp;
    while(cur != null) {
        if(cur.left == null) {
            if(pre != null && pre.val >= cur.val) 
                return false;
            pre = cur;
            cur = cur.right;
        }
        else {
            tmp = cur.left;
            while(tmp.right != null && tmp.right != cur)
                tmp = tmp.right;
            if(tmp.right == null) { // left child has not been visited
                tmp.right = cur;
                cur = cur.left;
            }
            else { // left child has been visited already
                tmp.right = null;
                if(pre != null && pre.val >= cur.val) 
                    return false;
                pre = cur;
                cur = cur.right;
            }
        }
    }
    return true;
}
greybeard
  • 2,249
  • 8
  • 30
  • 66
user36805
  • 41
  • 1
  • (Being `public`, `boolean isValidBST()` *needs* a comment that it temporarily *invalidates* the tree's structure - maybe even a deprecation; and an explanation when it's OK to use it, anyway.) – greybeard Jul 01 '17 at 17:58
1

"It's better to define an invariant first. Here the invariant is -- any two sequential elements of the BST in the in-order traversal must be in strictly increasing order of their appearance (can't be equal, always increasing in in-order traversal). So solution can be just a simple in-order traversal with remembering the last visited node and comparison the current node against the last visited one to '<' (or '>')."

Perception
  • 79,279
  • 19
  • 185
  • 195
Alexander
  • 11
  • 1
1

I got this question in a phone interview recently and struggled with it more than I should have. I was trying to keep track of minimums and maximums in child nodes and I just couldn't wrap my brain around the different cases under the pressure of an interview.

After thinking about it while falling asleep last night, I realized that it is as simple as keeping track of the last node you've visited during an inorder traversal. In Java:

public <T extends Comparable<T>> boolean isBst(TreeNode<T> root) {
    return isBst(root, null);
}

private <T extends Comparable<T>> boolean isBst(TreeNode<T> node, TreeNode<T> prev) {
    if (node == null)
        return true;

    if (isBst(node.left, prev) && (prev == null || prev.compareTo(node) < 0 ))
        return isBst(node.right, node);

    return false;
}
noxiousg
  • 11
  • 1
  • Only "half right": catches "low nodes" in right subtrees, misses "high nodes" on the left (doesn't even try and propagate "rightmost/highest" values back up). For a successful implementation, albeit using a "global" variable, see [Aayush Bahuguna's answer](https://stackoverflow.com/a/10909724/3789665), – greybeard Jul 01 '17 at 17:46
1

In Java and allowing nodes with same value in either sub-tree:

public boolean isValid(Node node) {
    return isValid(node, Integer.MIN_VALUE, Integer.MAX_VALUE);
}

private boolean isValid(Node node, int minLimit, int maxLimit) {
    if (node == null)
        return true;
    return minLimit <= node.value && node.value <= maxLimit
            && isValid(node.left, minLimit, node.value)
            && isValid(node.right, node.value, maxLimit);
}
Daniel Rodriguez
  • 607
  • 6
  • 11
1

Here is my answer in python, it has all the corner cases addressed and well tested in hackerrank website

""" Node is defined as
class node:
    def __init__(self, data):
        self.data = data
        self.left = None
        self.right = None
"""

def checkBST(root):
    return checkLeftSubTree(root, root.left) and checkRightSubTree(root, root.right)

def checkLeftSubTree(root, subTree):
    if not subTree:
        return True
    else:
        return root.data > subTree.data \
        and checkLeftSubTree(root, subTree.left) \ 
        and checkLeftSubTree(root, subTree.right) \
        and checkLeftSubTree(subTree, subTree.left) \
        and checkRightSubTree(subTree, subTree.right)

def checkRightSubTree(root, subTree):
    if not subTree:
        return True
    else:
        return root.data < subTree.data \ 
        and checkRightSubTree(root, subTree.left) \
        and checkRightSubTree(root, subTree.right) \
        and checkRightSubTree(subTree, subTree.right) \
        and checkLeftSubTree(subTree, subTree.left)
Deepak
  • 432
  • 1
  • 6
  • 15
1
bool BinarySearchTree::validate() {
    int minVal = -1;
    int maxVal = -1;
    return ValidateImpl(root, minVal, maxVal);
}

bool BinarySearchTree::ValidateImpl(Node *currRoot, int &minVal, int &maxVal)
{
    int leftMin = -1;
    int leftMax = -1;
    int rightMin = -1;
    int rightMax = -1;

    if (currRoot == NULL) return true;

    if (currRoot->left) {
        if (currRoot->left->value < currRoot->value) {
            if (!ValidateImpl(currRoot->left, leftMin, leftMax)) return false;
            if (leftMax != currRoot->left->value && currRoot->value < leftMax)  return false;
        }
        else
            return false;
    } else {
        leftMin = leftMax = currRoot->value;
    }

    if (currRoot->right) {
        if (currRoot->right->value > currRoot->value) {
            if(!ValidateImpl(currRoot->right, rightMin, rightMax)) return false;
            if (rightMin != currRoot->right->value && currRoot->value > rightMin)  return false;
        }
        else return false;
    } else {
        rightMin = rightMax = currRoot->value;
    }

    minVal = leftMin < rightMin ? leftMin : rightMin;
    maxVal = leftMax > rightMax ? leftMax : rightMax;

    return true;
}
0
bool ValidateBST(Node *pCurrentNode, int nMin = INT_MIN, int nMax = INT_MAX)
{
    return
    (
        pCurrentNode == NULL
    )
    ||
    (
        (
            !pCurrentNode->pLeftNode ||
            (
                pCurrentNode->pLeftNode->value < pCurrentNode->value &&
                pCurrentNode->pLeftNode->value < nMax &&
                ValidateBST(pCurrentNode->pLeftNode, nMin, pCurrentNode->value)
            )
        )
        &&
        (
            !pCurrentNode->pRightNode ||
            (
                pCurrentNode->pRightNode->value > pCurrentNode->value &&
                pCurrentNode->pRightNode->value > nMin &&
                ValidateBST(pCurrentNode->pRightNode, pCurrentNode->value, nMax)
            )
        )
    );
}
Mike X
  • 9
  • 3
  • My intention is to show another solution where the recursion _doesn't_ go into a branch unless it's valid. The current top answer _must_ go into a branch to check it's validity... – Mike X May 20 '12 at 04:22
  • *If* the "2nd checks of 3" where changed to `nMin < pCurrentNode->pLeftNode->value` and `pCurrentNode->pRightNode->value < nMax`, this was just overly complicated instead of "almost right". – greybeard Jul 01 '17 at 17:07
0

To find out whether given BT is BST for any datatype, you need go with below approach. 1. call recursive function till the end of leaf node using inorder traversal 2. Build your min and max values yourself.

Tree element must have less than / greater than operator defined.

#define MIN (FirstVal, SecondVal) ((FirstVal) < (SecondVal)) ? (FirstVal):(SecondVal)
#define MAX (FirstVal, SecondVal) ((FirstVal) > (SecondVal)) ? (FirstVal):(SecondVal)

template <class T>
bool IsValidBST (treeNode &root)
{

   T min,  max;
   return IsValidBST (root, &min, &max);
}

template <class T>
bool IsValidBST (treeNode *root, T *MIN , T *MAX)
{
   T leftMin, leftMax, rightMin, rightMax;
   bool isValidBST;

   if (root->leftNode == NULL && root->rightNode == NULL)
   {
      *MIN = root->element;
      *MAX = root->element;
      return true;
   }

  isValidBST = IsValidBST (root->leftNode, &leftMin, &leftMax);

  if (isValidBST)
    isValidBST = IsValidBST (root->rightNode, &rightMin, &rightMax);

  if (isValidBST)
  {
     *MIN = MIN (leftMIN, rightMIN);
     *Max = MAX (rightMax, leftMax);
  }

  return isValidBST;
}
Sach
  • 659
  • 8
  • 20
  • Probably should fix up your code -- you've made pre-processor macros of MIN and MAX, but then try to use MIN and MAX as variable (parameter) names. – MikeB Jan 31 '13 at 18:18
  • `you need go with below approach` - no: for a bottom-up approach, see `isBSTDivideAndConquer()` in [Lei Cao's answer](https://stackoverflow.com/a/32984413/3789665). – greybeard Jul 01 '17 at 18:24
0
bool isBST(struct node* root)
{
    static struct node *prev = NULL;
    // traverse the tree in inorder fashion and keep track of prev node
    if (root)
    {
        if (!isBST(root->left))
            return false;
        // Allows only distinct valued nodes
        if (prev != NULL && root->data <= prev->data)
            return false;
        prev = root;
        return isBST(root->right);
    }
    return true;
}

Works Fine :)

Matthias
  • 7,432
  • 6
  • 55
  • 88
0

Recursion is easy but iterative approach is better, there is one iterative version above but it's way too complex than necessary. Here is the best solution in c++ you'll ever find anywhere:

This algorithm runs in O(N) time and needs O(lgN) space.

struct TreeNode
{
    int value;
    TreeNode* left;
    TreeNode* right;
};

bool isBST(TreeNode* root) {
    vector<TreeNode*> stack;
    TreeNode* prev = nullptr;
    while (root || stack.size()) {
        if (root) {
           stack.push_back(root);
           root = root->left;
        } else {
            if (prev && stack.back()->value <= prev->value)
                return false;
            prev = stack.back();
            root = prev->right;                    
            stack.pop_back();
        }
    }
    return true;
}
shuais
  • 329
  • 3
  • 3
  • I think it does, can you construct a counter example? – shuais Feb 08 '13 at 10:06
  • Trivially: a two node tree that has the same integer in "value" of both nodes will still have your isBST() function returning "true". Since you're only returning false when value < value, you'll never detect it. Why do you think that test works to find duplicates? – MikeB Feb 10 '13 at 16:01
  • I thought duplicates are allowed in BST, but wikipedia seems to be against it. Then you're right, the < should be <=. – shuais Feb 11 '13 at 05:22
  • Using <= means that no node can have INT_MIN as its value. – MikeB Feb 11 '13 at 16:15
  • Well.. you're right, I hope you won't be my interviewer.. :P Fixable by a extra boolean flag. – shuais Feb 14 '13 at 06:12
0

I wrote a solution to use inorder Traversal BST and check whether the nodes is increasing order for space O(1) AND time O(n). TreeNode predecessor is prev node. I am not sure the solution is right or not. Because the inorder Traversal can not define a whole tree.

public boolean isValidBST(TreeNode root, TreeNode predecessor) {
    boolean left = true, right = true;
    if (root.left != null) {
        left = isValidBST(root.left, predecessor);
    }
    if (!left)
        return false;

    if (predecessor.val > root.val)
        return false;

    predecessor.val = root.val;
    if (root.right != null) {
        right = isValidBST(root.right, predecessor);
    }

    if (!right)
        return false;

    return true;

}
manub
  • 3,990
  • 2
  • 24
  • 33
  • `space O(1)` ignoring call stack - for a "true O(1) space" "solution", see [use 36805's answer](https://stackoverflow.com/a/26443551/3789665). – greybeard Jul 01 '17 at 18:04
0

Following is the Java implementation of BST validation, where we travel the tree in-order DFS and it returns false if we get any number which is greater than last number.

static class BSTValidator {
  private boolean lastNumberInitialized = false;
  private int lastNumber = -1;

  boolean isValidBST(TreeNode node) {
    if (node.left != null && !isValidBST(node.left)) return false;

    // In-order visiting should never see number less than previous
    // in valid BST.
    if (lastNumberInitialized && (lastNumber > node.getData())) return false;
    if (!lastNumberInitialized) lastNumberInitialized = true;

    lastNumber = node.getData();

    if (node.right != null && !isValidBST(node.right)) return false;

    return true;
  }
}
Hemant
  • 4,537
  • 8
  • 41
  • 43
0

Iterative solution.

private static boolean checkBst(bst node) {

    Stack<bst> s = new Stack<bst>();
    bst temp;
    while(node!=null){
        s.push(node);
        node=node.left;
    }
    while (!s.isEmpty()){
        node = s.pop();
        System.out.println(node.val);
        temp = node;
        if(node.right!=null){
            node = node.right;
            while(node!=null)
            {
                //Checking if the current value is lesser than the previous value and ancestor.
                if(node.val < temp.val)
                    return false;
                if(!s.isEmpty())
                    if(node.val>s.peek().val)
                        return false;
                s.push(node);
                if(node!=null)
                node=node.left;
            }
        }
    }
    return true;
}
Vathul
  • 1
  • 2
0

This works for duplicates.

// time O(n), space O(logn)
// pseudocode
is-bst(node, min = int.min, max = int.max):
    if node == null:
        return true
    if node.value <= min || max < node.value:
        return false
    return is-bst(node.left, min, node.value)
        && is-bst(node.right, node.value, max)

This works even for int.min and int.max values using Nullable types.

// time O(n), space O(logn)
// pseudocode
is-bst(node, min = null, max = null):
    if node == null:
        return true
    if min != null && node.value <= min
        return false
    if max != null && max < node.value:
        return false
    return is-bst(node.left, min, node.value)
        && is-bst(node.right, node.value, max)
hIpPy
  • 4,649
  • 6
  • 51
  • 65
0

Inspired by http://www.jiuzhang.com/solutions/validate-binary-search-tree/

There are two general solutions: traversal and divide && conquer.

public class validateBinarySearchTree {
    public boolean isValidBST(TreeNode root) {
        return isBSTTraversal(root) && isBSTDivideAndConquer(root);
    }

    // Solution 1: Traversal
    // The inorder sequence of a BST is a sorted ascending list
    private int lastValue = 0; // the init value of it doesn't matter.
    private boolean firstNode = true;
    public boolean isBSTTraversal(TreeNode root) {
        if (root == null) {
            return true;
        }

        if (!isValidBST(root.left)) {
            return false;
        }

        // firstNode is needed because of if firstNode is Integer.MIN_VALUE,
        // even if we set lastValue to Integer.MIN_VALUE, it will still return false
        if (!firstNode && lastValue >= root.val) {
            return false;
        }

        firstNode = false;
        lastValue = root.val;

        if (!isValidBST(root.right)) {
            return false;
        }

        return true;

    }

    // Solution 2: divide && conquer
    private class Result {
        int min;
        int max;
        boolean isBST;
        Result(int min, int max, boolean isBST) {
            this.min = min;
            this.max = max;
            this.isBST = isBST;
        }
    }

    public boolean isBSTDivideAndConquer(TreeNode root) {
        return isBSTHelper(root).isBST;
    }

    public Result isBSTHelper(TreeNode root) {
        // For leaf node's left or right
        if (root == null) {
            // we set min to Integer.MAX_VALUE and max to Integer.MIN_VALUE
            // because of in the previous level which is the leaf level,
            // we want to set the min or max to that leaf node's val (in the last return line)
            return new Result(Integer.MAX_VALUE, Integer.MIN_VALUE, true);
        }

        Result left = isBSTHelper(root.left);
        Result right = isBSTHelper(root.right);

        if (!left.isBST || !right.isBST) {
            return new Result(0,0, false);
        }

        // For non-leaf node
        if (root.left != null && left.max >= root.val
                && root.right != null && right.min <= root.val) {
            return new Result(0, 0, false);
        }

        return new Result(Math.min(left.min, root.val),
                Math.max(right.max, root.val), true);
    }
}
Lei Cao
  • 457
  • 6
  • 13
  • The last two statements of `boolean isBSTTraversal()` can be combined to `return isValidBST(root.right);`. In `Result isBSTHelper()`, requiring `root.val` to be *both* no greater than `left.max` *and* no smaller than `right.min` for a "false `Result`" doesn't seem quite right. – greybeard Jul 01 '17 at 18:20
0

One liner

bool is_bst(Node *root, int from, int to) {
   return (root == NULL) ? true :
     root->val >= from && root->val <= to &&
     is_bst(root->left, from, root->val) &&
     is_bst(root->right, root->val, to);
}

Pretty long line though.

samvel1024
  • 1,123
  • 4
  • 15
  • 39
0

Here's a solution in java from sedgewick's algorithm class. Check the full BST implementation here

I added some explanatory comments

private boolean isBST() {
    return isBST(root, null, null);

}

private boolean isBST(Node x, Key min, Key max) {
    if (x == null) return true;
    // when checking right subtree min is key of x's parent
    if (min != null && x.key.compareTo(min) <= 0) return false;
    // when checking left subtree, max is key of x's parent
    if (max != null && x.key.compareTo(max) >= 0) return false;
    // check left subtree and right subtree
    return isBST(x.left, min, x.key) && isBST(x.right, x.key, max);

}
Satyajit
  • 734
  • 7
  • 7
0
  • The iterative function checks iteratively whether given tree is a binary search tree.
  • The recurse function checks recursively whether given tree is a binary search tree or not.
  • In iterative function I use bfs for checking BST.
  • In recurse function I use dfs for checking BST.
  • Both solutions have a time complexity of O(n)
  • iterative solution has an advantage over recurse solution and that is iterative solution does early stopping.
  • Even recurse function can be optimized for early stopping by global flag value.
  • The idea of both the solution is that the left child should be within the range of -infinity to the value of its parent node whihch is the root node
  • The right child should be within the range of +infinity to the value of its parent node whihch is the root node
  • And go on comparing the current node's value within the range. If any node's value is not in the range then return False

    class Solution:
        def isValidBST(self, root):
            """
            :type root: TreeNode
            :rtype: bool
            """
            return self.iterative(root)
            # return self.recurse(root, float("inf"), float("-inf"))
    
        def iterative(self, root):
            if not root:
                return True
    
            level = [[root, -float("inf"), float("inf")]]
    
            while level:
                next_level = []
    
                for element in level:
                    node, min_val, max_val = element
                    if min_val<node.val<max_val:
                        if node.left:
                            next_level.append([node.left, min_val, node.val])
                        if node.right:
                            next_level.append([node.right, node.val, max_val])
                    else:
                        return False
                level = next_level
    
            return True
    
        def recurse(self, root, maxi, mini):
            if root is None:
                return True
    
            if root.val < mini or root.val > maxi:
                return False
    
            return self.recurse(root.left, root.val-1, mini) and self.recurse(root.right, maxi, root.val+1)
    
Jai
  • 3,211
  • 2
  • 17
  • 26
0

Python implementation example. This example uses type annotations. However since Node class uses itself we need to include as a first line of the module:

from __future__ import annotations

Otherwise, you will get name 'Node' is not defined error. This example also uses dataclass as an example. To check if it's BST it uses recursion for checking left and right nodes values.

"""Checks if Binary Search Tree (BST) is balanced"""

from __future__ import annotations
import sys
from dataclasses import dataclass

MAX_KEY = sys.maxsize
MIN_KEY = -sys.maxsize - 1


@dataclass
class Node:
    value: int
    left: Node
    right: Node

    @property
    def is_leaf(self) -> bool:
        """Check if node is a leaf"""
        return not self.left and not self.right


def is_bst(node: Node, min_value: int, max_value: int) -> bool:
    if node.value < min_value or max_value < node.value:
        return False
    elif node.is_leaf:
        return True

    return is_bst(node.left, min_value, node.value) and is_bst(
        node.right, node.value, max_value
    )


if __name__ == "__main__":
    node5 = Node(5, None, None)
    node25 = Node(25, None, None)
    node40 = Node(40, None, None)
    node10 = Node(10, None, None)

    # balanced tree
    node30 = Node(30, node25, node40)
    root = Node(20, node10, node30)
    print(is_bst(root, MIN_KEY, MAX_KEY))

    # unbalanced tree
    node30 = Node(30, node5, node40)
    root = Node(20, node10, node30)
    print(is_bst(root, MIN_KEY, MAX_KEY))
Vlad Bezden
  • 83,883
  • 25
  • 248
  • 179
0

BST example enter image description here

    public bool IsBinarySearchTree(TreeNode root)
    {
        return IsValid(root, long.MinValue, long.MaxValue);
    }

    private static bool IsValid(TreeNode node, long min, long max)
    {
        if (node == null)
        {
            return true;
        }

        if (node.Value >= max || node.Value <= min)
        {
            return false;
        }

        return IsValid(node.Left, min, node.Value) && IsValid(node.Right, node.Value, max);
    }

where TreeNode

   public class TreeNode
   {
       public int Value;
       public TreeNode Left;
       public TreeNode Right;

       public TreeNode(int value)
       {
           Value = value;
       }
   }

here's the detailed explanation https://codestandard.net/articles/validate-binary-search-tree/

GSerjo
  • 4,725
  • 1
  • 36
  • 55
0

We have to recursively ask each node if its left branch and right branch are valid binary search trees. The only thing each time we ask, we have to pass correct left and right boundaries:

enter image description here

class Solution:
    def is_bst(self,root:TreeNode):
        if not root:
            return True
        # left and right are boundaries
        def dfs(node,left,right):
            if not node:
                return True
            if not (node.val>left and node.val<right):
                return False
            # when we move right, we update the left, when we move left we update the right
            return dfs(node.left,left,node.val) and dfs(node.right,node.val,right)
        return dfs(root, float("-inf"), float("+inf"))
Yilmaz
  • 35,338
  • 10
  • 157
  • 202
0

Using inOrder Traversal..

First Adding the tree value to the array with inorder traversal.

Then iterate through the array which add a flag value true to split the elements after the root elements and before the root elements.

counter is added to check if the tree has elements with the same root value.

min and max is set to the range

var isValidBST = function(root) 
{

    
    if(!root) return false;
    
 
    let current = root;
    let data = [];
    let flag = false;
    let counter = 0;
    
    function check(node){
        if(node.left){
            check(node.left);
        }
        data.push(node.val);
        if(node.right){
            check(node.right);
        }
       
    }
    
    
    let min = Number.MIN_SAFE_INTEGER;
    let max = root.val;
    for(let i = 0; i < data.length; i++){
        
        if(data[i] == root.val){
            flag = true;
            counter++;
        }
        
        if(flag){
            if(data[i] < root.val || data[i] < max || counter > 1){
                return false;
            }
            else{
                
                max = data[i];
            }
            
            
        }
        else{
            if(data[i] > root.val || data[i] <= min|| counter > 1){
                return false
            }
            else {
                min = data[i]
            }
        }
    }
    
    return true;
    

};
Suraj Rao
  • 29,388
  • 11
  • 94
  • 103
sooraj ks
  • 11
  • 2
  • Why special case `root.val`? Why handle values "before" `root.val` any different from those after? – greybeard Dec 29 '21 at 06:55
  • root.val is to identify the values before the root elements. Inorder traversal gives you an array of tree elements in ascending order. So all elements before root.val should be lesser and values after root should be greater. – sooraj ks Dec 29 '21 at 11:55
0

Recursive solution:

isBinary(root)
    {
        if root == null 
          return true
       else if( root.left == NULL and root.right == NULL)
          return true
       else if(root.left == NULL)
           if(root.right.element > root.element)
               rerturn isBInary(root.right)
        else if (root.left.element < root.element)
              return isBinary(root.left)
        else
              return isBInary(root.left) and isBinary(root.right)

    }
NoobEditor
  • 15,563
  • 19
  • 81
  • 112
  • When would it return false? – Rubab Zahra Sarfraz May 26 '16 at 17:18
  • This wouldn't even return `true` if syntax was checked before execution: `rerturn` and `isBInary` should prevent that. No language is mentioned, indentation is inconsistent, there seem to be paths to the end of the block/function without explicit return (which is where a python function without an explicit return would return `None`, interpreted as `False` in a "boolean context".) Probably worse, it shows the most common error: ((.1(.3.))2.) is *not* a valid search tree, but would pass tests *if there is a left (right) subtree, it's root element must be smaller(larger) than this* tried above. – greybeard Jul 01 '17 at 16:34
  • what if the left -> right element is greater than the root. In that case, the above function returns true where it should be false. – Arun GK Oct 05 '17 at 00:36
0
// using inorder traverse based Impl
bool BinarySearchTree::validate() {
    int val = -1;
    return ValidateImpl(root, val);
}

// inorder traverse based Impl
bool BinarySearchTree::ValidateImpl(Node *currRoot, int &val) {
    if (currRoot == NULL) return true;

    if (currRoot->left) {
        if (currRoot->left->value > currRoot->value) return false;
        if(!ValidateImpl(currRoot->left, val)) return false;
    }

    if (val > currRoot->value) return false;
    val = currRoot->value;

    if (currRoot->right) {
        if (currRoot->right->value < currRoot->value) return false;
        if(!ValidateImpl(currRoot->right, val)) return false;
    }
    return true;
}
-1

Here is the iterative solution without using extra space.

Node{
     int value;
     Node right, left
  }

  public boolean ValidateBST(Node root){
    Node currNode = root;
    Node prevNode = null;
    Stack<Node> stack = new Stack<Node>();
    while(true){
        if(currNode != null){
            stack.push(currNode);
            currNode = currNode.left;
            continue;
        }
        if(stack.empty()){
            return;
        }
        currNode = stack.pop();
        if(prevNode != null){
            if(currNode.value < prevNode.value){
                return false;
            }
        }
        prevNode = currNode;
        currNode = currNode.right;
    }
}
Swapnil Tailor
  • 129
  • 1
  • 6
-1
 private void validateBinarySearchTree(Node node) {
    if (node == null) return;

    Node left = node.getLeft();
    if (left != null) {
        if (left.getData() < node.getData()) {
            validateBinarySearchTree(left);
        } else {
            throw new IllegalStateException("Not a valid Binary Search tree");
        }
    }

    Node right = node.getRight();
    if (right != null) {
        if (right.getData() > node.getData()) {
            validateBinarySearchTree(right);
        } else {
            throw new IllegalStateException("Not a valid Binary Search tree");
        }
    }
}
iMobaio
  • 266
  • 4
  • 12
-3

Here is my recursive solution written in JavaScript

function isBST(tree) {
  if (tree === null) return true;

  if (tree.left != undefined && tree.left.value > tree.value) {
    return false;
  }

  if (tree.right != undefined && tree.right.value <= tree.value) {
    return false;
  }

  return isBST(tree.left) && isBST(tree.right);
}
satnam
  • 1,457
  • 4
  • 23
  • 43
-3
boolean isBST(Node root) {
    if (root == null) { return true; }
    return (isBST(root.left) && (isBST(root.right) && (root.left == null || root.left.data <= root.data) && (root.right == null || root.right.data > root.data));
}
Lee
  • 103
  • 1
  • 11