This is the answer for leet code question 270(Find Closest Value in BST) in Python. I could'nt grasp what and how the tree.value in this code works.
def findClosestValueInBst(tree, target):
return findClosestValueInBstHelper(tree, target, closest)
def findClosestValueInBstHelper(tree, target, closest):
if tree is None:
return Closest
if abs(target - closest) > abs(target - tree.value):
closest = tree.value
if target < tree.value:
return findClosestValueInBstHelper(tree.left, target, closest)
elif target > tree.vlaue:
return findClosestValueInBstHelper(tree.right, target, closest)
else:
return closest
There is a class for TreeNode that's defined by LeetCode, and you don't have to add that to the Solution:
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
This'd pass through:
# 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:
def closestValue(self, root, target):
a_value = root.val
child = root.left if target < a_value else root.right
if not child:
return a_value
b_value = self.closestValue(child, target)
return min((b_value, a_value), key=lambda x: abs(target - x))
Also, there is no tree.value, it should be tree.val I guess.
References
For additional details, you can see the Discussion Board. There are plenty of accepted solutions with a variety of languages and explanations, efficient algorithms, as well as asymptotic time/space complexity analysis1, 2 in there.
Related
I've prepared a recursive tree-traversal based solution to the "same tree" problem. However, I'm encountering an error on use cases involving None values. Why is my approach incorrect and how should I be altered to handle the use case?
class Solution(object):
def traversal(self,root):
visited = []
if root:
if root.left:
visited.extend(self.traversal(root.left))
visited.append(root.val)
if root.right:
visited.extend(self.traversal(root.right))
return visited
def isSameTree(self, p, q):
"""
:type p: TreeNode
:type q: TreeNode
:rtype: bool
"""
p_path = self.traversal(p)
q_path = self.traversal(q)
print(p_path, q_path)
return p_path == q_path
Use case: input([1,1][1,null,1]), output(true), stdout([1,1], [1,1])
Two different trees can have the same in-order traversal, but different structure, so it's not sufficient to completely rely on "traversal" in your code.
Hint: trees are only the same if they have the same root and (recursively) the same left subtree and (recursively) the same right subtree.
Gave up on the recursive attempt, but an iterative one worked.
# 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 isSameTree(self, p, q):
"""
:type p: TreeNode
:type q: TreeNode
:rtype: bool
"""
stack = [(p,q)]
while stack:
p_curr, q_curr = stack.pop()
# both p and q exist
if p_curr and q_curr:
# validity check
if p_curr.val != q_curr.val:
return False
# left check
if p_curr.left and q_curr.left:
stack.append((p_curr.left, q_curr.left))
elif p_curr.left and not q_curr.left:
return False
elif not p_curr.left and q_curr.left:
return False
# right check
if p_curr.right and q_curr.right:
stack.append((p_curr.right, q_curr.right))
elif p_curr.right and not q_curr.right:
return False
elif not p_curr.right and q_curr.right:
return False
elif p_curr:
# only p exists, invalid
return False
elif q_curr:
# only q exists, invalid
return False
return True
I am writing code to solve the following Leetcode solution:
https://leetcode.com/problems/symmetric-tree/
#THIS FIRST CHUNK OF CODE IS JUST TO BUILD A BINARY TREE!
from collections import deque
class TreeNode:
def __init__(self, val):
self.val = val
self.left = None
self.right = None
def insert(self, val):
# Compare the new value with the parent node
if self.val:
if val <= self.val:
if self.left is None:
self.left = TreeNode(val)
else:
self.left.insert(val)
elif val >= self.val:
if self.right is None:
self.right = TreeNode(val)
else:
self.right.insert(val)
else:
self.val = val
def PrintTree(self):
if self.left:
self.left.PrintTree()
print(self.val),
if self.right:
self.right.PrintTree()
#THIS IS THE CODE TO SOLVE THE LEETCODE PROBLEM
class Solution:
def isSymmetric(self, root: TreeNode) -> bool:
queue = deque()
if not root:
return []
if root.left:
queue.append(root.left)
if root.right:
queue.append(root.right)
right_subt = []
left_subt = []
while queue:
level_length = len(queue)
for _ in range(level_length // 2):
node = queue.popleft()
left_subt.append(node.val)
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)
for _ in range((level_length - (level_length // 2))):
node = queue.popleft()
right_subt.append(node.val)
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)
print(queue)
if left_subt != right_subt.reverse():
return False
return True
root = TreeNode(1)
root.insert(2)
root.insert(2)
root.insert(3)
root.insert(4)
root.insert(4)
root.insert(3)
root.PrintTree()
x=Solution()
Solution.isSymmetric(x,root)
My code fails the first input: root = [1,2,2,3,4,4,3] ; it should return True but it is retuning False, and I am trying to debug it.
In my code above I build a tree using class TreeNode, and I try to print the queue, however what I get is: deque([<__main__.TreeNode object at 0x7fe9381dc340>, <__main__.TreeNode object at 0x7fe9381dc820>])
Any ideas how I can print the queue to show the node values?
Most elegant would be to define the __repr__ function for the TreeNode class, e.g.
def __repr__(self):
return f"Node {self.val}"
This determines how the TreeNode class is printed. In this case you get
deque([Node 2, Node 3])
Then you can also adapt it according to your needs, e.g. if you want to print left and right in addition to the value.
Below in the solution class, I have an implementation of an inorder traversal (left, root, right).
For some reason I am entering into an infinte loop and I wonder if it is becaue of the way python handels consecutive if if/else statements?
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = righ
class Solution:
def inorderTraversal(self, root: TreeNode) -> List[int]:
out = []
stack = []
if root is None:
return out
else:
stack.append(root)
while stack != []:
temp = stack.pop()
if temp.right:
stack.append(temp.right)
if temp.left:
a = temp.left
stack.append(temp)
stack.append(a)
else:
out.append(temp.val)
return out
I wrote this code and when I use print I see that I get the leaves. However, the final return from the function is None and not the sum of the leaves, which is supposed to be 7 in this example. I'd be happy to know whats wrong here. Thank you !
class Node:
def __init__(self, val=None):
self.left = None
self.right = None
self.val = val
def sum_leafs(tree):
if tree is None:
return 0
if tree.right and tree.left:
sum_leafs(tree.right)
sum_leafs(tree.left)
elif tree.right or tree.left:
if tree.right:
sum_leafs(tree.right)
elif tree.left:
sum_leafs(tree.left)
elif tree.right is None and tree.left is None:
return sum_leafs(tree.left) + 1
node = Node(10)
node.right = Node(2)
node.left = Node(11)
node.left.right = Node(5)
print(sum_leafs(node))
You forgot to add + when you sum the branches (left/right) and also you forgot to access val which is the most crucial thing for the whole thing to work.
Further, the logic can be simplified:
def sum_leafs(tree):
if tree is None:
return 0
if not tree.right and not tree.left:
return tree.val
return sum_leafs(tree.right) + sum_leafs(tree.left)
You are not adding the sums together or returning them. This can also be done with a method in the class:
class Node:
def __init__(self, val=None):
self.left = None
self.right = None
self.val = val
def sum(self):
s = 0
if self.left is not None:
s += self.left.sum()
if self.right is not None:
s += self.right.sum()
return self.val + s
node = Node(10)
node.right = Node(2)
node.left = Node(11)
node.left.right = Node(5)
print(node.sum())
returns:
28
You are not properly returning the calculated leaf sums. Try this:
class Node:
def __init__(self, val=None):
self.left = None
self.right = None
self.val = val
def sum_leafs(tree):
if tree is None:
return 0
elif tree.right and tree.left:
return sum_leafs(tree.right) + sum_leafs(tree.left)
elif tree.right or tree.left:
if tree.right:
return sum_leafs(tree.right)
elif tree.left:
return sum_leafs(tree.left)
elif tree.right is None and tree.left is None:
return tree.val
node = Node(10)
node.right = Node(2)
node.left = Node(11)
node.left.right = Node(5)
print(sum_leafs(node))
7
node
First I'm going to update your Node interface so that it's possible to set left and right branches when creating nodes -
class Node:
def __init__(self, val=None, left=None, right=None):
self.left = left
self.right = right
self.val = val
This allows us to create tress more ergonomically, such as -
t = Node(10, Node(11, None, Node(5)), Node(2))
traverse
Now we write a generic traverse procedure. This allows us to separate 1) the traversal of our tree from 2) the intended operation we want to perform on each tree element -
def traverse(tree):
if tree is None:
return
else:
yield tree.val
yield from traverse(tree.left)
yield from traverse(tree.right)
Now the need for sum_leafs disappears. We have decoupled traversal logic from summing logic. We can calculate the sum of leafs with a simple combination of sum and traverse -
print(sum(traverse(t)))
# 28
don't repeat yourself
Or, instead of summing the values, we could write a search function to find the first value that passes a predicate -
def search(test, tree):
for val in traverse(tree):
if test(val):
return val
print(search(lambda x: x < 10, t))
# 5
print(search(lambda x: x > 99, t))
# None
Or, we could simply collect each value into a list -
print(list(traverse(t)))
# [ 10, 11, 5, 2 ]
As you can see, removing the traversal logic from each function that depends on our tree can be a huge help.
without generators
If you don't like generators, you can write the eager version of traverse which always returns a list. The difference now is there is no way to partially traverse the tree. Note the similarities this program shares with the generator version -
def traverse(t):
if t is None:
return [] # <-- empty
else:
return \
[ t.val
, *traverse(t.left) # <-- yield from
, *traverse(t.right) # <-- yield from
]
print(traverse(t))
# [ 10, 11, 5, 2 ]
I have been working on trying to implement the function all_bigger below but I am not sure if there are flaws in my logic. To my understanding, BST's are organized having the smallest values on the left side so I would only need to check the left side of the BST. Is there a better way of writing this or is my code incorrect?
class BSTNode:
"""A node is a BST """
def __init__(self: 'BSTNode', item, left, right):
self.item, self.left, self.right = item, left, right
def all_bigger(self, value):
"""
>>> bst = BSTNode(5, BSTNode(4), BSTNode(6))
>>> all_bigger(bst, 2)
True
"""
while self.left:
if self.left > value:
self.value = self.left:
else:
return False
return True
Your code is almost correct, with some minor bugs. Corrected code:
class BSTNode:
"""A node is a BST """
def __init__(self, item, left = None, right = None):
self.item, self.left, self.right = item, left, right
def all_bigger(self, value):
"""
>>> bst = BSTNode(5, BSTNode(4), BSTNode(6))
>>> all_bigger(bst, 2)
True
"""
root = self
while(root!=None):
if root.item > value:
root = root.left
else:
return False
return True
bst = BSTNode(5, BSTNode(4,BSTNode(1, None, None),None), BSTNode(6,None,None)) # Returns False
print(bst.all_bigger(2))
IIUC your question is to see if all the nodes in the BST are bigger than a certain value.
A simple way to do is to find the node with the minimum value in the BST and compare it with the other value. The smallest node is going to be the left-most node.
A typical BST node looks like this
# A binary tree node
class Node:
# Constructor to create a new node
def __init__(self, key):
self.data = key
self.left = None
self.right = None
And yes, you're right. The tree does not need to be searched fully, ie, the right subtrees can be skipped. This is how you find the node with the minimum value.
def minValue(node):
current = node
# loop down to find the lefmost leaf
while(current.left is not None):
current = current.left
return current.data
This can be slightly tweaked to solve your problem
def all_bigger(node, val):
current = node
# loop down to find the lefmost leaf
while(current.left is not None):
current = current.left
# Check if the current node value is smaller than val
if current.data < val:
return False
return True
You need to update the node after every comparison. Kindly check the below code:
class BSTNode:
"""A node is a BST """
def __init__(self: 'BSTNode', item, left, right):
self.item, self.left, self.right = item, left, right
def all_bigger(self, value):
"""
>>> bst = BSTNode(5, BSTNode(4), BSTNode(6))
>>> all_bigger(bst, 2)
True
"""
while self.item:
if self.left > value:
self.item = self.left:
else:
return False
return True
All values in a subtree are greater than X if and only if
The value in the node is greater than X, and
All values in its left subtree (if it exists) are greater than X
Assuming an empty tree is None:
def all_bigger(self, value):
return self.value > value and self.left and self.left.all_bigger(value)