2

I am trying to solve a binary search tree problem, but I can't pass all of the test cases. I need to return true if the tree is a binary search tree, otherwise, I need to return false. Can anyone tell me what I am doing wrong?

'''
class node:
    def __init__(self, data):
        self.data = data
        self.left = None
        self.right = None
'''

def checkBST(root):
    if root.left == None and root.right == None:
        return True
    if root == None:
        return True
    if root.left != None:
        if root.left.data < root.data:
            return True
    else:
        return False
    if root.right != None:
        if root.right.data > root.data:
            return True
        else:
            return False
    return chckBST(root.left) and chckBST(root) and chckBST(root.right)
cs95
  • 379,657
  • 97
  • 704
  • 746
user2645029
  • 63
  • 1
  • 9
  • why do you call `chckBST(root)` again, it should be by the first call from the test case itself right? i think recursive calls should be for left and right only – Yazan Jul 03 '17 at 12:39

3 Answers3

5

You've a lot of redundant if conditions in your code. You can simplify it like so:

def checkBST(root):
    if root == None or (root.left == None and root.right == None):
        return True

    elif root.right == None:
        return root.left.data < root.data and checkBST(root.left)

    elif root.left == None:
        return root.right.data >= root.data and checkBST(root.right)

    return checkBST(root.left) and checkBST(root.right)

First, check for all the None conditions. Short circuiting in python guarantees that if the first condition is False, the second will not be evaluated. This allows you to write succinct statements such as return root.left.data < root.data and checkBST(root.left).

Finally, in the event that neither left nor right nodes are None, do not call checkBST(root) again. This leads to infinite recursion.

cs95
  • 379,657
  • 97
  • 704
  • 746
  • This implementation will return a false positive for the test case mentioned by Artur. – Dvd848 Dec 27 '21 at 21:01
  • This is a wrong implementation, we should check 'maxof(root.left) < root.data' instead, BST means that the key in any node is larger than the keys in all nodes in that node's left subtree and smaller than the keys in all nodes in that node's right subtree. – Sayan Dey Jan 26 '23 at 08:02
1

As mentioned by Artur, you need to check that all the left nodes are less than or equal to the current node (assuming you allow duplicate values, otherwise just less than), and all the right nodes are larger than the current node.

You can do that by recursively passing down the minimum allowed and maximum allowed values and testing child nodes against these values.

def check_bst(root) -> bool:
    def is_bst_internal(root, min_allowed_val, max_allowed_val) -> bool:
        if root is None:
            return True

        if min_allowed_val is not None and root.data <= min_allowed_val:
            return False

        if max_allowed_val is not None and root.data > max_allowed_val:
            return False

        return is_bst_internal(root.left, min_allowed_val, root.data) and is_bst_internal(root.right, root.data, max_allowed_val)
    return is_bst_internal(root, None, None)

When we go left, we pass the current value as the maximum allowed value, since any higher value we meet on the left branch will fail the check. When we go right, we pass the current value as the minimum value, since any lower (or equal) value will fail the check. None means that there is no maximum/minimum.

Dvd848
  • 288
  • 2
  • 8
0

So the reason you're not passing some of the tests is because you're only checking one level deep. For instance, if there is a tree such that it has a root.left.right.data > root.data, then your code won't catch that. There is a good explanation here

But the gist is:

  • Your code will pass this

All left children are smaller and all right children are bigger

  • But it won't pass this Notice the right child of 2 > root.data

I think this solution solves it (sorry for answering a Python question with JS code, but I'm sure you'll get the idea):

function checkBST(root) {
    let isBST = true;
    let BSTUtil = r => {
        let left, right
        if(r.left) // Bottom out on the left side
            left = BSTUtil(r.left)
        if(r.right) // Bottom out on the right side
            right = BSTUtil(r.right)

        if(left > r.data) // Compare with parent
            isBST = false
        if(right < r.data) // Compare with parent
            isBST = false

        // Return MAX from branch
        if(!left && !right)
            return r.data
        else if(!left)
            return Math.max(right, r.data)
        else
            return Math.max(left, right, r.data)
    }
    BSTUtil(root)
    return isBST;
}

Also, please don't use this code, it uses O(n) space to solve the problem, and I'm sure I can find a more efficient solution if I spend some time on the question.

Artur Grigio
  • 5,185
  • 8
  • 45
  • 65
  • Looks like this implementations returns `true` for `checkBST({data: 10, left: null, right: {data: 12, left: {data: 2, left: null, right: null}, right: null}})`, even though the right branch contains a value lower than the root value. – Dvd848 Dec 27 '21 at 20:59