I am looking at LeetCode problem 98. Validate Binary Search Tree:
Given the
root
of a binary tree, determine if it is a valid binary search tree (BST).A valid 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.
What is the problem with the below provided code for validating the binary tree property with preorder traversal?
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution(object):
def isValidBST(self, root):
"""
:type root: TreeNode
:rtype: bool
"""
def preorder(root):
if root.left!=None:
if root.left < root.val:
preorder(root.left)
else:
return False
if root.right!=None:
if root.right>root.val:
preorder(root.right)
else:
return False
t= preorder(root)
return t!=False
It is returning False
for the Test case where root=[2,1,3]
CodePudding user response:
You need to traverse the right-sub-tree only when the left-sub-tree is a valid one.
def preorder(root):
if root.left!=None:
if root.left < root.val:
preorder(root.left)
else:
return False
if root.right!=None (and left-sub-tree is valid):
if root.right>root.val:
preorder(root.right)
else:
return False
Note: I don't know Python. Understand the comment while checking right-sub-tree.
CodePudding user response:
Several issues:
root.left < root.val
is comparing a node with an integer. This should beroot.left.val < root.val
. Same for the right side check.Although
preorder
returnsFalse
when there is a violation, the caller that makes the recursive call ignores this return value and happily continues. This is wrong. It should stop the traversal when the recursive call returnsFalse
, and itself returnFalse
to its caller.Not the main issue, but as
preorder
returnsFalse
, it should better returnTrue
in the remaining cases, so you can be sure thatpreorder
returns a boolean, and don't have to treatNone
or compare the return value explicitly withFalse
.The algorithm only checks whether a direct child of a node has a value that is not conflicting with the value of the parent, but that is not enough for validating a BST. All the values in the left subtree must be less than parent's value, not just the left child. So even if the above problems are fixed, this algorithm will wrongly say this BST is valid:
4 / 1 \ 9 <-- violation (because of 4)
To solve the last point, you need to revise the algorithm: realise that when you are deep in a BST, there is a window of values that a subtree in a valid BST can have: there is a lower limit and an upper limit. In the above example the right child of the node 1 could only have a value in the range (1, 4).
Here is an implementation as a spoiler:
class Solution(object): def isValidBST(self, root): def preorder(root, low, high): return not root or ( low < root.val < high and preorder(root.left, low, root.val) and preorder(root.right, root.val, high) ) return preorder(root, -float("inf"), float("inf"))