What is wrong with this iterative solution in validating Binary Search Tree? - python

The goal is, 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.
The problem setting is the same as here
# 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
"""
level=[root]
while level:
for k in level:
if k.left:
if k.left >= k.val:
return False
if k.right:
if k.right <= k.val:
return False
level=[leaf for n in level for leaf in (n.left,n.right) if leaf]
return True
The above solution could not work for the case [2,1,3] which I believe the bug is located at this part after some debugging processes
if k.left:
if k.left >= k.val:
return False
What is wrong with it? Thanks in advance for any help.

There are a couple of issues with your code:
In the lines if k.left >= k.val: and if k.right <= k.val: you are comparing nodes to values, which I assume is not your intention.
Assuming the above is corrected, the general logic only compares the values of children with those of their immediate parents, which is not enough to satisfy the part of the problem specification stating, "The left subtree of a node contains only nodes with keys less than the node's key", or the symmetrical part of the spec regarding the right subtree. To satisfy this, you need to track the ancestral bounds with which a given node's val attribute must comply.
Here's an example of a modification to your code that would work as an iterative solution:
# 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
"""
level=[(root,None,None)]
while level:
level2 = []
for k,floor,ceil in level:
if k.left:
if k.left.val >= k.val or floor is not None and k.left.val <= floor:
return False
level2.append((k.left,floor,k.val))
if k.right:
if k.right.val <= k.val or ceil is not None and k.right.val >= ceil:
return False
level2.append((k.right,k.val,ceil))
level = level2
return True
t = TreeNode(2, TreeNode(1), TreeNode(3))
x = Solution()
print(x.isValidBST(t))
Ouput:
True
Explanation:
instead of storing each non-null node at a given level, we store a tuple for each such node including the node itself as well as floor and ceil values (set to None for root) that will allow us to carry forward (or downward as we descend the levels of the tree) the bounds to which a given subtree must conform.
When we traverse leftward via a non-null left attribute, we overwrite ceil with the immediate parent's val attribute, and for rightward traversal via a non-null right attribute we overwrite floor.

Related

Leetcode Problem 1038. Binary Search Tree to Greater Sum Tree --> Python

I am doing the above leetcode problem in Python. Typically what I do is I solve the problem in a jupyter notebook and then copy and paste it into the leetcode solution box once I am done with it. I am having issues with this problem, however.
The problem definition is defined below:
Given the root of a Binary Search Tree (BST), convert it to a Greater Tree such that every key of the original BST is changed to the original key plus sum of all keys greater than the original key in BST.
As a reminder, a binary search tree is a tree that satisfies these constraints:
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.
A sample input and output for the problem is shown below
Input: root = [4,1,6,0,2,5,7,null,null,null,3,null,null,null,8]
Output: [30,36,21,36,35,26,15,null,null,null,33,null,null,null,8]
Furthermore the problem solution is set up as follows
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def bstToGst(self, root: TreeNode) -> TreeNode:
I am confused as to how to approach this problem. Initially I thought I would do some sort of looping through the list provided. Upon reading some sample responses from the discussion, however, I see that commands such as root.right and root.left are used. How do I go about doing this in a jupyter notebook? I have no expereince with TreeNodes so I want to this the problem the right way and learn the fundamental concept instead of brute forcing through it another way. All help is greatly appreciated.
Thanks
Define an iterator function to traverse the nodes in reverse order, Then accumulate the total going backwards through the nodes and assign the values to each node:
class Solution:
def revNodes(self,node):
if node.right: yield from self.revNodes(node.right)
yield node
if node.left: yield from self.revNodes(node.left)
def bstToGst(self, root):
total = 0
for node in self.revNodes(root):
node.val = total = node.val + total
output:
data = [4,1,6,0,2,5,7,None,None,None,3,None,None,None,8]
nodes = [v if v is None else TreeNode(v) for v in data]
for i,node in enumerate(nodes):
if not node: continue
if 2*i+1<len(nodes): node.left = nodes[2*i+1]
if 2*i+2<len(nodes): node.right = nodes[2*i+2]
root = nodes[0]
print(root) # BEFORE
4
__/ \_
1 6
/ \ / \
0 2 5 7
\ \
3 8
Solution().bstToGst(root)
print([node.val if node else None for node in nodes])
[30, 36, 21, 36, 35, 26, 15, None, None, None, 33, None, None, None, 8]
print(root) # AFTER
30
__/ \__
36 21
/ \ / \
36 35 26 15
\ \
33 8
Note that, in order to print the tree, I had to add a repr() method to the TreeNode class
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
def __repr__(self):
nodeInfo = lambda n:(str(n.val),n.left,n.right)
return "\n".join(printBTree(self,nodeInfo,isTop=False))
The printBTree function is from another answer I provided in the past here

Wrong Answer in 'Is this a Binary Search Tree' on HackerRank

For the purposes of this challenge, we define a binary tree to be a binary search tree with the following ordering requirements:
The value of every node in a node's left subtree is less than the data value of that node.
The value of every node in a node's right subtree is greater than the data value of that node.
Given the root node of a binary tree, can you determine if it's also a binary search tree?
Complete the function in your editor below, which has parameter: a pointer to the root of a binary tree. It must return a boolean denoting whether or not the binary tree is a binary search tree. You may have to write one or more helper functions to complete this challenge.
Input Format
You are not responsible for reading any input from stdin. Hidden code stubs will assemble a binary tree and pass its root node to your function as an argument.
Constraints:
0<=data<=10^4
Output Format
You are not responsible for printing any output to stdout. Your function must return true if the tree is a binary search tree; otherwise, it must return false. Hidden code stubs will print this result as a Yes or No answer on a new line.
My Code:
""" Node is defined as
class node:
def __init__(self, data):
self.data = data
self.left = None
self.right = None
"""
def check_binary_search_tree_(root):
if root is None or (root.left is None and root.right is None):
return True
if root.left.data>=root.data or root.right.data<=root.data:
return False
check_binary_search_tree_(root.left)
check_binary_search_tree_(root.right)
return True
Why am I getting Wrong Answer?
The problem with your code is
first you didn't do :
return check_binary_search_tree_(root.left) and check_binary_search_tree_(root.right)
next even if you do that, you are forgetting to keep the root's value in mind while checking the BST property for left and right children. It could be that your left child is totally a good BST but it fails to be a BST when you consider its parent. Look at the below example:
6
4 7
2 8
The subtree rooted at 4 is a good BST but fails when you consider its root's value of 6.
The solution is then to check the proper range of values at each node i.e.
left_limit < root.data < right_limit
You could write your function as :
def check_binary_search_tree_(root, min = -math.inf, max = math.inf):
if root is None:
return True
if root.data > min and root.data < max:
return check_binary_search_tree_(root.left, min, root.data) and check_binary_search_tree_(root.right, root.data, max)
return False
check_binary_search_tree_(root.left)
check_binary_search_tree_(root.right)
You don't return a result of these recursive functions. Try to do:
return check_binary_search_tree_(root.left) and check_binary_search_tree_(root.right)
Full code example that works:
def check_binary_search_tree_(root):
def isValid(node, lower=float('-inf'), upper=float('inf')):
if not node:
return True
if node.data <= lower or node.data >= upper:
return False
return isValid(node.left, lower, node.data) and isValid(node.right, node.data, upper)
return isValid(root)

Leetcode 426. Convert Binary Search Tree to Sorted Doubly Linked List?

I am very confused about the question No.426 on leetcode, as I think my answer is right. But after running it shows I am wrong. Below is the question and my original answer:
"""
# Definition for a Node.
class Node:
def __init__(self, val, left, right):
self.val = val
self.left = left
self.right = right
"""
class Solution:
def treeToDoublyList(self, root):
"""
:type root: Node
:rtype: Node
"""
if root:
sign = True
stack = []
node = root
while stack or node:
if node:
stack.append(node)
node = node.left
else:
node = stack.pop()
if sign:
pre,head = node, node
else:
pre.right = node
node.left = pre
pre = node
node = node.right
head.left = pre
pre.right = pre
return head
else:
return None
Could someone help me to figure out what's wrong with my codes? Any comment or suggestion will be so appreciated.
I see two problems with the code.
First is that inside your if sign: block you need to set sign = False since you only want to initialize head once and execute that block only the first time. (Not sure why the variable is called sign, perhaps first would be more appropriate, or just reusing a head = None for that condition would have worked too.)
The second bug is smaller and affects the last link in the list to make it circular. You want to set pre.right = head instead of pre, so that the last node of the list points back at the first, not at itself.
I haven't really tested this, so it's possible I'm missing something, but it looks to me that this should be enough to fix this code.

Function finding the deepest sum of a binary search tree

I'm trying to make a function in python were I don't want to change the BST class at all to do this. The function is to find the sum of the path of the root to the node with the highest depth. If there is multiple nodes that have the same depth I'm looking for the maximum sum of that and return it.
What I got so far (Using a basic BST Class)
class BTNode(object):
def __init__(self, data, left=None, right=None):
self.data = data
self.left = left
self.right = right
After trying to make an algorithm to solve this for a while, I came up with a couple above but they were fails and I didn't know how to code it.
ALGORITHM:
I think this would work:
We start from the root. (The base case I think should be whenever we hit a leaf as in when there is no child in a node so no left or right child, and also when there is a left no right, or when there is a right no left)
I check the left subtree first and get the depth of it, we'll call it depth_L as well with the sum. Then I check the right subtree and we will call it depth_R then get the depth of it and its sum.
The second condition would be to check if they are equal, if they are equal then its easy and we just take the max sum of either two depths. Else we would see who has the highest depth and try to get the sum of it.
Now were I don't know how to do is a couple things.
1: I never learned optional parameters so I'm trying to avoid that while trying this exercise but I don't think I can and I'd really appreciate someone could show me some cool helper functions instead.
2: Its not the total sum of the right side or the left side its the path that I need. Its kind of confusing to think of a way to get just the path
(Heres my renewed attempt using the algorithm above):
def deepest_sum(self, bsum = 0, depth = 0):
# The root is in every path so
bsum = bsum + self.data
depth = depth + 1
# Base case whenever we find a leaf
if self.left == None and self.right == None:
result = bsum,depth
elif self.left is not None and self.right is None:
pass
elif self.left is None and self.right is not None:
pass
else:
# Getting the left and right subtree's depth as well as their
# sums, but once we hit a leaf it will stop
# These optional parameters is messing me up
if self.left:
(sums1, depth_L) = self.left.deepest_sum(bsum,depth)
if self.right:
(sums2, depth_R) = self.right.deepest_sum(bsum,depth)
# The parameter to check if they are equal, the highest goes through
if depth_L == depth_R:
result = max(sums1, sums2), depth_R
else:
if depth_L > depth_R:
result = sums1, depth_L
else:
result = sums2, depth_R
return result
Stuck on the parts i mentioned. Heres an example:
>>> BST(8, BST(7, BST(10), BST(11)), BST(6, BST(11), BST(9, None, BST(14)))
37 (depth 3 is the highest so 8 + 6 + 9 + 14 is the path)
Sorry i put BST i just forgot, its a binary Tree not BST.
I know mine gives a tuple but I can always make a helper function to fix that, I just thought it'd be easier keeping track of the nodes.
You could simplify the implementation quite a bit if the function doesn't need to be a method of BTNode. Then you could keep track of the depth & sum, iterate past the leaf and return the current depth and sum. Additionally if you return (depth, sum) tuples you can compare them directly against each other with max:
class BTNode(object):
def __init__(self, data, left=None, right=None):
self.data = data
self.left = left
self.right = right
def deepest_sum(node, depth=0, current=0):
# Base case
if not node:
return (depth, current)
depth += 1
current += node.data
return max(deepest_sum(node.left, depth, current),
deepest_sum(node.right, depth, current))
tree = BTNode(8, BTNode(7, BTNode(10), BTNode(11)), BTNode(6, BTNode(11), BTNode(9, None, BTNode(14))))
print(deepest_sum(tree))
Output:
(4, 37)

what is wrong with my binary search tree validation code?

According to the definition, a Binary Tree must satisfy the following conditions:
1. The left subtree of a node contains only nodes with keys less than
the the node's key.
2. The right subtree of a node contains only nodes with keys greater than the node's key.
3. Both the left and right subtrees must also be binary search trees.
My code is returning True for the input [10 ,5, 15, #, #, 6, 20] but it's incorrect, it must return False.
The input follows a level order traversal, where '#' signifies a path terminator where no node exists below.
Here is the tree:
10
/ \
5 15
/ \
6 20
Here is my code :
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
def isValidBST(self, root)
"""
:type root: TreeNode
:rtype: bool
"""
if not root:
return True
else:
if root.left and root.right:
return root.left.val < root.val < root.right.val and \
self.isValidBST(root.left) and self.isValidBST(root.right)
elif root.left and not root.right:
return root.left.val < root.val and self.isValidBST(root.left)
elif root.right and not root.left:
return root.right.val > root.val and self.isValidBST(root.right)
else:
return True
Consider a BST where A is the root value, B is the value at the root of its left subtree, and C is the value at the root of the right subtree under that. Your code will verify that A > B, and that B < C. But it does not check to see if A > C.
Or, from your example: It checks that 5<10, 10<15, 6<15, and 15<20, but does not check that 6>10.
Recall that the definition of a BST talks about all nodes in a subtree, not just the root.
Your algorithm doesn't implement frist two conditions properly. You should compare root value with maximum of left subtree and minimum of right subtree.
Alternatively, you can do an inorder traversal of the tree which should be in ascending order in binary search tree.

Categories