Function finding the deepest sum of a binary search tree - python

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)

Related

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)

Find minimum depth of binary tree solution does not work when one side of tree is null

I am trying to understand why my solution to find the minimum depth of binary tree does not work when one side of the tree is None.
There's already a question asked on this here - Why won't my solution work to find minimum depth of a binary tree? but the answer there still does not make me understand.
My implementation code is as below.
class Solution:
def minDepth(self, root: 'TreeNode') -> 'int':
if root is None:
return 0
left = self.minDepth(root.left)
right = self.minDepth(root.right)
min_depth = min(left, right)
return 1 + min_depth
When the last line is modified to the following, it works.
if left == 0 or right == 0:
return 1 + left + right
return 1 + min_depth
My question is, why do you need to check if one side is None or not if in the end, you sum them all up anyway - return 1 + left + right?
Test case is
class TreeNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None
# [1, 2]
root = TreeNode(1)
root.left = TreeNode(2)
solution = Solution()
solution.minDepth(root)
My code returns 1 where it should return 2.
EDIT
The depth of the tree is defined as the number of nodes in the shortest path from the root of the tree to a leaf node.
When you are at a node that has only one child, then in your first code version, the min_depth for that node will be 0 (since one of the recursive calls will return 0).
That is indeed wrong, because the node is not a leaf. It would only be correct if the node were a leaf (without children).
In your example, the root is such a node (with one child). This is what happens:
minDepth(root) is called
....minDepth(root.left) is called
........minDepth(root.left.left) is called and returns 0, because it isNone`
........minDepth(root.left.right) is called and returns 0, because it isNone`
........min_depth = min(left, right) evaluates to 0
........the return value is 1 for minDepth(root.left)
....minDepth(root.right) is called and returns 0, because it is None
....min_depth = min(left, right) evaluates to 0, which is wrong.
....the final return value is thus 1 (wrong).
When you are in the situation where either left or right is 0, you need to get the minDepth of the remaining child and add 1 to it. That is why it works when you add this:
if left == 0 or right == 0:
return 1 + left + right

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.

Python recursion - how to exit early

I've been playing with BST (binary search tree) and I'm wondering how to do an early exit. Following is the code I've written to find kth smallest. It recursively calls the child node's find_smallest_at_k, stack is just a list passed into the function to add all the elements in inorder. Currently this solution walks all the nodes inorder and then I have to select the kth item from "stack" outside this function.
def find_smallest_at_k(self, k, stack, i):
if self is None:
return i
if (self.left is not None):
i = self.left.find_smallest_at_k(k, stack, i)
print(stack, i)
stack.insert(i, self.data)
i += 1
if i == k:
print(stack[k - 1])
print "Returning"
if (self.right is not None):
i = self.right.find_smallest_at_k(k, stack, i)
return i
It's called like this,
our_stack = []
self.root.find_smallest_at_k(k, our_stack, 0)
return our_stack[k-1]
I'm not sure if it's possible to exit early from that function. If my k is say 1, I don't really have to walk all the nodes then find the first element. It also doesn't feel right to pass list from outside function - feels like passing pointers to a function in C. Could anyone suggest better alternatives than what I've done so far?
Passing list as arguments: Passing the list as argument can be good practice, if you make your function tail-recursive. Otherwise it's pointless. With BST where there are two potential recursive function calls to be done, it's a bit of a tall ask.
Else you can just return the list. I don't see the necessity of variable i. Anyway if you absolutely need to return multiples values, you can always use tuples like this return i, stack and this i, stack = root.find_smallest_at_k(k).
Fast-forwarding: For the fast-forwarding, note the right nodes of a BST parent node are always bigger than the parent. Thus if you descend the tree always on the right children, you'll end up with a growing sequence of values. Thus the first k values of that sequence are necessarily the smallest, so it's pointless to go right k times or more in a sequence.
Even in the middle of you descend you go left at times, it's pointless to go more than k times on the right. The BST properties ensures that if you go right, ALL subsequent numbers below in the hierarchy will be greater than the parent. Thus going right k times or more is useless.
Code: Here is a pseudo-python code quickly made. It's not tested.
def findKSmallest( self, k, rightSteps=0 ):
if rightSteps >= k: #We went right more than k times
return []
leftSmallest = self.left.findKSmallest( k, rightSteps ) if self.left != None else []
rightSmallest = self.right.findKSmallest( k, rightSteps + 1 ) if self.right != None else []
mySmallest = sorted( leftSmallest + [self.data] + rightSmallest )
return mySmallest[:k]
EDIT The other version, following my comment.
def findKSmallest( self, k ):
if k == 0:
return []
leftSmallest = self.left.findKSmallest( k ) if self.left != None else []
rightSmallest = self.right.findKSmallest( k - 1 ) if self.right != None else []
mySmallest = sorted( leftSmallest + [self.data] + rightSmallest )
return mySmallest[:k]
Note that if k==1, this is indeed the search of the smallest element. Any move to the right, will immediately returns [], which contributes to nothing.
As said Lærne, you have to care about turning your function into a tail-recursive one; then you may be interested by using a continuation-passing style. Thus your function could be able to call either itself or the "escape" function. I wrote a module called tco for optimizing tail-calls; see https://github.com/baruchel/tco
Hope it can help.
Here is another approach: it doesn't exit recursion early, instead it prevents additional function calls if not needed, which is essentially what you're trying to achieve.
class Node:
def __init__(self, v):
self.v = v
self.left = None
self.right = None
def find_smallest_at_k(root, k):
res = [None]
count = [k]
def helper(root):
if root is None:
return
helper(root.left)
count[0] -= 1
if count[0] == 0:
print("found it!")
res[0] = root
return
if count[0] > 0:
print("visiting right")
find(root.right)
helper(root)
return res[0].v
If you want to exit as soon as earlier possible, then use exit(0).
This will make your task easy!

Determine if a binary tree rooted at a node is a max-heap [duplicate]

This question already has answers here:
How to test multiple variables for equality against a single value?
(31 answers)
Closed 8 years ago.
I'm trying to determine if a binary tree rooted at a node is a max-heap, and to do so I followed the rules of the heap property for a max-heap which states:
Max-heap:
All nodes are either greater than or equal to each of its children
My Idea of the implementation:
If at the node given as the parameter of is_max_heap has no right or left node than return True
Otherwise, if the value of the node is greater than the value of the left and right node, then call the function again on both the right and left nodes.
Return False otherwise.
My code:
class BTNode:
'''A generic binary tree node.'''
def __init__(self, v):
'''(BTNode, int) -> NoneType
Initialize a new BTNode with value v.
'''
self.value = v
self.left = None
self.right = None
def is_max_heap(node):
'''(BTNode) -> bool
Return True iff the binary tree rooted at node is a max-heap
Precondition: the tree is complete.
'''
if node.left and node.right is None:
return True
else:
if node.value > node.left.value and node.value > node.right.value:
return is_max_heap(node.left) and is_max_heap(node.right)
else:
return False
if __name__ == '__main__':
l1 = BTNode(7)
l2 = BTNode(6)
l3 = BTNode(8)
l1.left = l2
l1.right = l3
print(is_max_heap(l1))
So, under if __name__ == '__main__': I created three nodes, with values, 7, 6, and 8. The first node has a left and right node. So the tree would look like this:
7
/ \
6 8
This does not satisfy the max-heap property so it should return False. However running my code returns True and I can't figure out where I might of went wrong. If anyone can help me that would be really appreciated.
You have not thought of the case when there is only one child. Make sure your program works right on these two trees, too - one is a min heap, the other is a max heap:
2 1
/ /
1 2
Also learn to set brackets correctly; you have made the classic mistake True and 42 == 42; which is True.
Consider handling the two maybe-nonexistant childs the same way.
if left is not None:
if not <check max heap property for left subtree>: return False
if right is not None:
if not <check max heap property for right subtree>: return False
return True
The missing function should compare to the current node and recurse into the subtree if necessary.

Categories