Lately, I started "leetcode" for studying programming. Sometimes, I encounter the question which is related to TreeNode.
https://leetcode.com/problems/longest-univalue-path/
I usually run code in local to make sure if my code work. But those questions require me to prepare for TreeNode in advance, otherwise, I can not run in local. I don't know how to build TreeNode from a list.
I want to make TreeNode from a list by Python, like here.
class TreeNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None
input: [5,4,5,1,1,5]
output:
TreeNode{val: 5, left: TreeNode{val: 4, left: TreeNode{val: 1, left: None, right: None}, right: TreeNode{val: 1, left: None, right: None}}, right: TreeNode{val: 5, left: TreeNode{val: 5, left: None, right: None}, right: None}}
I know we can make sure whether the code work or not on leetcode. However, I think it's slow for me to check the code on leetcode. I would like to run my code in local. I hope you will help me.
Take a look at LeetCode's official explanation https://support.leetcode.com/hc/en-us/articles/360011883654-What-does-1-null-2-3-mean-in-binary-tree-representation- of how their serialized formatting of a binary tree into the kind of list you see in their test cases works. If you want to run your solution against those test cases locally, you'll also need to write some code (or I'm sure you can find some online) that will input a serialized list, build the tree, and return the tree's root TreeNode so you can pass it to your find_longest_univalue_path function.
Guess this is what you need:
class TreeNode(object):
def __init__(self, x):
self.val = x
self.left = None
self.right = None
def creatBTree(data, index):
pNode = None
if index < len(data):
if data[index] == None:
return
pNode = TreeNode(data[index])
pNode.left = creatBTree(data, 2 * index + 1) # [1, 3, 7, 15, ...]
pNode.right = creatBTree(data, 2 * index + 2) # [2, 5, 12, 25, ...]
return pNode
Say you are cracking pathSum, populate the tree by calling
lst = [5,4,8,11,None,13,4,7,2,None,None,None,1]
root = creatBTree(lst, 0)
Here is just beautified StefanPochmann's solution which was described at
LeetCode's Help Center
class TreeNode:
def __init__(self, val, left=None, right=None):
self.val = val
self.left = left
self.right = right
def __repr__(self):
return 'TreeNode({})'.format(self.val)
def deserialize(string):
if string == '[]':
return None
nodes = [None if val == 'null' else TreeNode(int(val))
for val in string.strip('[]').split(',')]
kids = nodes[::-1]
root = kids.pop()
for node in nodes:
if node:
if kids:
node.left = kids.pop()
if kids:
node.right = kids.pop()
return root
if __name__ == '__main__':
tree = deserialize('[3,9,20,null,null,15,7]')
assert tree == TreeNode(3, TreeNode(9), TreeNode(20, TreeNode(15), TreeNode(7)))
Here's a drop-in replacement for the incomplete class LeetCode provides in questions such as https://leetcode.com/problems/invert-binary-tree/
import json
class TreeNode:
def __init__(self, val, left=None, right=None):
self.val = val
self.left = left
self.right = right
def __repr__(self):
# Shrink the long json string by removing unnecessary lines
t = '\n'.join([l for l in self.json_repr.split('\n')
if '[' not in l and ']' not in l])
return t.replace(',','')
#property
def json_repr(self):
if self.val is None:
return 'None'
# Recursively construct a json-compliant representation
if self.left is None:
text = f"[{self.val}]"
else:
text = f"[{self.val}, [{self.left.json_repr}, {self.right.json_repr}]]"
return json.dumps(json.loads(text), indent=1)
def from_list(l):
nodes = [TreeNode(v) for v in l]
kids = nodes[::-1]
root = kids.pop()
for node in nodes:
if node:
if kids:
node.left = kids.pop()
if kids:
node.right = kids.pop()
return root
t = TreeNode.from_list([4,2,7,1,3,6,9])
print(t)
Returns:
4
2
1
3
7
6
9
Related
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.
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 am trying to create generator which will give me values from next depth level of BST. Let's say that our tree will look like:
I would like to get result for following code like:
for level in tree:
print(level)
# 3
# (1,5)
# (2,4,7)
I was testing different variations of yield usage, but none of them gave me expected result. Here is code which I ended with:
class Node:
def __init__(self, element):
self.left = None
self.right = None
self.data = element
def __iter__(self):
yield self.data
if self.left and self.right:
yield from self.left.__iter__() and self.right.__iter__()
elif self.left:
yield from self.left.__iter__()
elif self.right:
yield from self.right.__iter__()
else:
pass
def add_element(self, element):
if self.data > element:
if self.left is None:
self.left = Node(element)
else:
self.left.add_element(element)
else:
if self.right is None:
self.right = Node(element)
else:
self.right.add_element(element)
def get_structure(self):
return (self.left.get_structure() if self.left else None, self.data, self.right.get_structure() if self.right else None)
This is given example from top:
from node import *
tree = Node(3)
tree.add_element(5)
tree.add_element(1)
tree.add_element(2)
tree.add_element(4)
tree.add_element(7)
print('Structure:',tree.get_structure()) #result: (None, 1, (None, 2, None)), 3, ((None, 4, None), 5, (None, 7, None)))
print('Iteration:', end=" ") #reslut: 3 5 7 / expected result: 3 (1,5) (2,4,7)
for level in tree:
print(level, end=" ")
Explain me please how can I fix my __iter__ method to get values from each depth level of tree?
I would like to get values from tree as generator to iterate over them. In this case yield just gives me a single value. Function print_tree works as expected - it shows values from smallest to biggest. How to get similar result, but with catching them one by one? This is my BST implementation:
class Node:
def __init__(self, element):
self.left = None
self.right = None
self.data = element
def add_element(self, element):
if self.data > element:
if self.left is None:
self.left = Node(element)
else:
self.left.add_element(element)
else:
if self.right is None:
self.right = Node(element)
else:
self.right.add_element(element)
def print_tree(self):
if self.left: self.left.print_tree()
print(self.data, end=' ')
if self.right: self.right.print_tree()
def get_values(self):
if self.left: self.left.get_values()
yield self.data
if self.right: self.right.get_values()
def get_structure(self):
return (self.left.get_structure() if self.left else None, self.data, self.right.get_structure() if self.right else None)
Code for testing:
from node import *
x = Node(3)
x.add_element(5)
x.add_element(1)
x.add_element(7)
print(x.get_structure()) #result: ((None, 1, None), 3, (None, 5, (None, 7, None)))
x.print_tree() #result: 1 3 5 7
z = x.get_values()
print(list(z)) #result: [3]
Could you please explain me where am I making a mistake and how can I correct it?
First you yield all elements from the left subtree, then the node value and finally all elements from the right subtree
def get_values(self):
if self.left:
yield from self.left.get_values()
yield self.data
if self.right:
yield from self.right.get_values()
I want to define two functions, one that prints a tree out from a nested list and the other that prints a tree from a flat list.
For exaple, if we have the lists
[5, [10, None, None], [11, [2, None, None],[6, None, None]]],
and [None, 5, 10, 11, None, None, 2, 6], we would produce a tree that looks like
10
5
15
11
22
This is the Binary Tree implementation
class BinaryTree:
def __init__(self, data):
self.data = data
self.left = None
self.right = None
def get_left(self):
return self.left
def get_right(self):
return self.right
def set_left(self, tree):
self.left = tree
def set_right(self, tree):
self.right = tree
def set_data(self, data):
self.data = data
def get_data(self):
return self.data
def create_string(self, spaces):
info = ' ' * spaces + str(self.data)
if self.left != None:
info += self.left.create_string(spaces+4)
if not self.right == None:
info += self.right.create_string(spaces+4)
return info
def __str__(self):
representation = self.create_string(0)
return representation
I basically want to convert the list into a tree because there is a create string function in the Binary Tree class
A simple recursive function would allow you to create the nested lists into a btree:
def create_tree(data):
if not data:
return data
d, l, r = data
btree = BinaryTree(d)
btree.set_left(create_tree(l))
btree.set_right(create_tree(r))
return btree
>>> print(create_tree([10, [5, None, None], [15, [11, None, None],[22, None, None]]]))
10
(l) 5
(r) 15
(l) 11
(r) 22
Though personally I would update the __init__() method of the BinaryTree class to optionally take the left and right:
class BinaryTree(object):
def __init__(self, data, left=None, right=None):
self.data = data
self.left = left
self.right = right
Then the recursive function becomes:
def create_tree(data):
if not data:
return data
d, l, r = data
return BinaryTree(d, create_tree(l), create_tree(r))
It's unclear what the mapping from the flat list is to the tree structure.