Minimum Element in Binary Search Tree - python

Given a Binary Search Tree. The task is to find the minimum element in this given BST.
Example 1:
Input:
5
/ \
4 6
/ \
3 7
/
1
Output: 1
Example 2:
Input:
9
\
10
\
11
Output: 9
Your Task:
The task is to complete the function minValue() which takes root as the argument and returns the minimum element of BST. If the tree is empty, there is no minimum element, so return -1 in that case.
My Code:
def minValue(root):
if root is None:
return -1
elif root.left is None:
return root.data
else:
minValue(root.left)
This code is giving me the output None with every testcase whereas if I change my minValue(root.left) in the else condition to return minValue(root.left), I'm getting correct answer. Can anyone tell me the reason as to why this is happening?

Every Python function returns something. If the function exits without a return then the returned value is None. Your code returns -1 if the first if statement is true. It returns root.data if the elif is true. Otherwise it returns None, since the else branch is taken and that returns nothing. It calls minValue but that doesn't actually do anything because you don't return anything there. After the function finishes the code just falls through to the end - and therefore Python returns None.

You haven't added a return statement in the second case, hence the output shows None as nothing was actually returned. Just change it to
def minValue(root):
if root is None:
return -1
elif root.left is None:
return root.data
else:
return minValue(root.left)

Related

LeetCode 98: Validate Binary Search Tree

I have looked at this code line by line maybe 100 times and I am stumped. Why doesn't this work????
Problem: input of [5,4,6,null,null,3,7] (this is a BST with 5 being the root and 4 and 6 being its left and right nodes)
returns True when it should return False (3 should be not be to the right of parent node 5). False should be returned at the first nested if statement in the while loop.
def isValidBST(self, root: Optional[TreeNode]) -> bool:
if not root:
return True
# BFS method
current_node = root
queue = []
queue.append(current_node)
while len(queue) > 0:
current_node = queue.pop(0)
if current_node.left:
if (current_node.val > current_node.left.val) and (root.val > current_node.left.val):
queue.append(current_node.left)
else:
return False
if current_node.right:
if (current_node.val < current_node.right.val) and (root.val < current_node.right.val):
queue.append(current_node.right)
else:
return False
return True
The tree for which your code fails is:
5
/ \
4 6
/ \
3 7
When current_node is 6, your code checks that root.val > current_node.left.val, which means it checks that 5 > 3. This is true. And so it wrongly concludes there is no problem there, yet there is.
You may now think to just change the direction of that comparison, but there is a logical error in your approach: it is not enough to compare the root with every node in its subtree. For instance, in the following tree you should detect that 3 is violating the BST property, even though it is not in conflict with the root:
2
\
5
\
6
/
3
The conflict is with the value 5, which is neither the parent of 3, nor the root.
In conclusion, a BFS traversal is not really an ideal tool to verify a BST. Although it surely can be done, it is more natural to use DFS, as it allows to carry down the (accumulated) limitations that will apply to every node in the subtree.

Subset Sum using Sets (Python)

I'm trying to solve the Subset Sum problem using Set and recursion in python.
I've found a lot of solutions with an array, but none with a set.
Here is my code:
def checkForSubSet(set, sum):
if len(set) == 0 or sum < 0:
return False
e = set.pop()
if sum == e:
return True
return checkForSubSet(set, sum - e) or checkForSubSet(set, sum)
if __name__ == '__main__':
set = {3, 34, 4, 12, 5, 2}
sum = 17
if (checkForSubSet(set, sum) == True) :
print("Found a subset with given sum")
else :
print("No subset with given sum")
sometimes its works and sometimes not... any idea?
ty for any help!
Your basic error is that you pop() a value from the input set. This means that in all subsequent calls you will not have that value available. This is easily seen with a print statement, where I've replaced sum and set with names that don't clash with builtins:
def checkForSubSet(components, target):
print(f"{components=} {target=}")
if len(components) == 0 or target< 0:
return False
e = components.pop()
if target == e:
return True
return checkForSubSet(components, target - e) or checkForSubSet(components, target)
>>> checkForSubSet({3,2,1}, 4)
components={1, 2, 3} target=4
components={2, 3} target=3
components={3} target=1
components=set() target=-2
components=set() target=1
components=set() target=3
components=set() target=4
False
We see that the set gets ordered. 1 is tested first, and then popped off. And so on until 3 is popped off and then, hitting the base case, the function returns False. It tries the alternative cases - but the set (which persists throughout) no longer has items in it. Thus, as it goes back up the tree it is testing against an empty set.
Recursion is always about a base case and an iterative case:
def has_subset(components: Set[int], target: int) -> bool:
print(f"{components=} {target=}")
# Base Case: check for truth once the set is empty
if 0 == target:
return True
# Iterative Case: iterate through each option you have for reducing the size of the set by one
else:
return any(has_subset(components - {item}, target - item) for item in components)
Here, we check the base case of an empty set. If we have an empty set and the target is 0, we return true. Otherwise, we return false.
The iterative case is (almost always) more interesting. Here, we simply iterate through all elements of the set, and check what has_subset() returns if we remove one item and reduce our target by that item. any() lets us return the first result we get that is True, or False if we exhaust all options. Note, however, that we are using the construct components - {item} which takes your initial set and returns a new set that includes all the elements except those in the set {item}. Since this is a new set, it does not fall prey to the previous problem when we recurse with it.
There are optimizations that can happen (what happens if your choice makes target a negative number?), but this should still work.

i have implemened this binary search but it returns none for the given test data [duplicate]

This question already has answers here:
Why does my recursive function return None?
(4 answers)
Closed 6 months ago.
def binary_search(input_array, value):
right_search=[]
left_search=[]
"""Your code goes here."""
if len(input_array)%2==0:
mid_ind=(len(input_array)/2)-1
else:
mid_ind=int(len(input_array)/2)
if input_array[mid_ind]==value:
return mid_ind
elif input_array[mid_ind]<value:
for ri in range(mid_ind+1,len(input_array)):
right_search.append(input_array[ri])
if right_search==[]:
return -1
binary_search(right_search,value)
elif input_array[mid_ind]>value:
for li in range(0,mid_ind):
left_search.append(input_array[li])
if left_search==[]:
return -1
binary_search(left_search,value)
test_list = [1,3,9,11,15,19,29]
test_val1 = 25
test_val2 = 15
print (binary_search(test_list, test_val1))
print (binary_search(test_list, test_val2))
it prints out none for both the test cases.i have used recursion for every sub array in main array.so that if mid element not matches the value to be found.It creates a left or right sub array according to value and then using recursion
Assuming a return value of -1, means the element being searched for is not present in the list, and 0, means the element is present, the reason the binary_search function is returning None, is because when recursion occurs, the return value of the function is not being returned to its caller, therefore when the recursion loop finishes, it has nothing to return.
The fix to this problem would be to add the return keyword before the recursive calls:
def binary_search(input_array, value):
right_search=[]
left_search=[]
"""Your code goes here."""
if len(input_array)%2==0:
mid_ind=(len(input_array)/2)-1
else:
mid_ind=int(len(input_array)/2)
if input_array[mid_ind]==value:
return mid_ind
elif input_array[mid_ind]<value:
for ri in range(mid_ind+1,len(input_array)):
right_search.append(input_array[ri])
if right_search==[]:
return -1
return binary_search(right_search,value)
elif input_array[mid_ind]>value:
for li in range(0,mid_ind):
left_search.append(input_array[li])
if left_search==[]:
return -1
return binary_search(left_search,value)
test_list = [1,3,9,11,15,19,29]
test_val1 = 25
test_val2 = 15
print (binary_search(test_list, test_val1))
print (binary_search(test_list, test_val2))

Python - Iterative searchtree implementation

I am trying to implement an iterative function, which searches a given search-tree for an integer, and reports back whether that integer exist within the search-tree.
So far it works for returning True if the value exists, but runs into a "list index out of range" error when searching for values not existant within the search-tree.
return [l,v,r]
def left(l) :
return l[0]
def right(l) :
return l[2]
def value(l) :
return l[1]
def empty() :
return []
def iterative_check_for_elem(val,tree):
while not tree == False:
if val == value(tree):
return True
break
elif val < value(tree):
tree = left(tree)
elif val > value(tree):
tree = right(tree)
return False
test_tree = node(node(node(empty(),30,empty()),40,node(empty(),45,empty())),50,node(node(empty(),55,empty()),60,node(empty(),70,empty())))
print(iterative_check_for_elem(45,test_tree))
45 works in the call to print, 47 runs into the error.
I can not figure out what is going wrong honestly.
Your tree has a bunch of empty nodes in it (created by empty()), and your search code doesn't deal with them properly. While an empty list is falsey, it's not equal to False, which your code seems to expect. Try rewriting the loop condition as:
while tree:
...
Or you could be more explicit and do a check like:
while len(tree) > 0:
...

Recursion and return statements [duplicate]

This question already has answers here:
Why does my recursive function return None?
(4 answers)
Closed 8 months ago.
I'm fairly new to Python and recursive functions as a whole, so pardon my ignorance.
I am trying to implement a binary search tree in Python and have the following insert method (taken out of a class):
def insert(self, key, root=None):
'''Inserts a node in the tree'''
if root == None:
root = self.root
if root.key == None:
self._update(root, key)
return 0
else:
tmp = root
if key > tmp.key: # we work with the right subtree
self.insert(key, root=tmp.right)
elif key < tmp.key: # we work with the left subtree
self.insert(key, root=tmp.left)
else: # key already exists
return 0
I'm not sure if this is legible, but it traverses the tree until it gets to a None value and updates the node with the key to insert.
Now, the method works nicely and correctly creates a BST from scratch. But there's a problem with the return statements, as it only returns 0 if there is no recursion performed.
>>> bst.insert(10)
0
>>> bst.insert(15)
>>> bst.root.right.key
15
>>>
"Inserting" the root key again returns 0 (from line 15) the way it should.
>>> bst.insert(10)
0
I can't figure out why this happens. If I put a print statement in line 6, it executes correctly, yet it just won't return anything past the first insertion. Why is this? (I'm pretty sure I'm missing some basic information regarding Python and recursion)
Thanks for your help,
Ivan
P.S.: I've read that recursion is not the best way to implement a BST, so I'll look into other solutions, but I'd like to know the answer to this before moving on.
On your recursive lines, you do not return anything. If you want it to return 0, you should replace them with lines like:
return self.insert(key, root=tmp.left)
instead of just
self.insert(key, root=tmp.left)
You are inside a function and want to return a value, what do you do? You write
def function():
return value
In your case you want to return the value returned by a function call, so you have to do.
def function():
return another_function()
However you do
def function():
another_function()
Why do you think that should work? Of course you use recursion but in such a case you should remember the Zen of Python which simply says:
Special cases aren't special enough to break the rules.
You need a return statement in your recursive case. Try this adjustment.
def insert(self, key, root=None):
'''Inserts a node in the tree'''
if root == None:
root = self.root
if root.key == None:
self._update(root, key)
return 0
else:
tmp = root
if key > tmp.key: # we work with the right subtree
return self.insert(key, root=tmp.right)
elif key < tmp.key: # we work with the left subtree
return self.insert(key, root=tmp.left)
else: # key already exists
return 0

Categories

Resources