Given the following tree:
I should return the level order traversal of the tree from left to right:
so the above example would output a list of lists :
[ [3], [9,20], [15,7] ]
I wrote the following code, idea is storing the node value and its depth recursively in a Queue then iterate the Queue tuples and put the in intermediate list O if no more node of same depth append O to output and empty O and so on. However my code Timeout any help?
import queue
class Solution:
def levelOrder(self, root: TreeNode) -> List[List[int]]:
def helper(root,res,level):
if not root:
return res
l=level+1
res.put((root.val,level))
helper(root.left,res,l)
helper(root.right,res,l)
res=queue.Queue()
helper(root,res,0)
d=1
output=[]
node,depth=res.get()
output.append([node])
while res:
o=[]
node,depth=res.get()
while d ==depth:
o.append(node)
node,depth=res.get()
else:
d+=1
output.append(o)
return output
Here is my code for the Breadth First Search (BFS) Iterative Implementation with nodes in each level in the final output is under a single list:
class TreeNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None
class Solution:
def BFS(self, root) -> int:
level=1
current=(root, level)
s=set()
result=[]
Q = [current]
while Q:
current=Q.pop()
level=current[1]
if current[0] not in s:
result.append([current[0].val, level])
s.add(current[0])
if current[0].left:
Q.insert(0,(current[0].left, level+1))
if current[0].right:
Q.insert(0,(current[0].right, level+1))
output=[]
temp=[]
level=1
for val in result:
if val[1]==level:
temp.append(val[0])
elif val[1] > level:
output.append(temp)
temp=[val[0]]
level+=1
output.append(temp)
return output
Testing:
n1=TreeNode(3)
n2=TreeNode(9)
n3=TreeNode(20)
n4=TreeNode(6)
n5=TreeNode(15)
n6=TreeNode(7)
n1.left=n2
n1.right=n3
n2.left=n4
n3.left=n5
n3.right=n6
sol1=Solution()
print(sol1.BFS(n1))
[[3], [9, 20], [6, 15, 7]]
Thanks for the answer from san. The solution helps me solve problem 107 of leetcode. I revised a little bit based on my understanding. There are two ways to solve this question but I prefer to use BFS fashion. This revised version compresses both value and level in the queue. It provides more flexibility comparing with only print the value of each node in the tree, as other tutorials provided.
# 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 levelOrderBottom(self, root: TreeNode) -> List[List[int]]:
if root is None:
return None
level = 1
q = []
q.append((root,level)) # push both node and level.
save = []
while q:
cur = q.pop(0)
cur_node = cur[0]
cur_level = cur[1]
# print(cur_node.val)
# print(cur_level)
save.append([cur_node.val, cur_level])
if cur_node.left:
q.append((cur_node.left, cur_level+1))
if cur_node.right:
q.append((cur_node.right, cur_level+1))
print(save) # once print, you will have the idea about how to reorgnized the required output.
level = 1
output = []
temp = []
for i in range(len(save)):
cur = save[i]
#print(cur)
if cur[1] == level:
temp.append(cur[0])
if cur[1] != level:
output.insert(0, temp)
temp = []
temp.append(cur[0])
level = level + 1
if i == len(save)-1:
output.insert(0, temp)
return output
You can use the below logic , to print out nodes in BFS .
If you also need , you modify the method to return a list as well .
def levelOrder(root):
qroot = []
print(root.info,end=' ')
if root.left:
qroot.append(root.left)
if root.right:
qroot.append(root.right)
while(qroot):
tmp = qroot[0]
if tmp.left:
qroot.append(tmp.left)
if tmp.right:
qroot.append(tmp.right)
print (tmp.info,end=' ')
qroot.pop(0)
return
Instead of printing the values , you can directly keep appending the value to a new list and return the same .
Related
I am trying to solve the Leetcode problem: 102. Binary Tree Level Order Traversal and hit a snag. My code below does not give the correct output and I have been trying to figure out what is the issue since it is not appending the last level in the tree. I would appreciate it someone can assist in making this code work.
# 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 levelOrder(self, root: Optional[TreeNode]) -> List[List[int]]:
while not root:
return []
queue = [root]
result = [[queue[0].val]]
while queue:
nodes = queue
level_nodes = []
temp = []
for node in nodes:
level = queue.pop(0)
if node.left:
level_nodes.append(level.left.val)
temp.append(node.left)
if node.right:
level_nodes.append(level.right.val)
temp.append(node.right)
queue = temp
result.append(level_nodes)
return result
Input: root = [3,9,20,null,null,15,7]
Expected Output: [[3],[9,20],[15,7]]
Output I am getting: [[3],[9,20],[]]
Reference: https://leetcode.com/problems/binary-tree-level-order-traversal/description/
I have been able to solve the problem and leave it for reference anyone who is doing it in this way (Not trying to use deque from collisions library). This solution was accepted by LeetCode.
# 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 levelOrder(self, root: Optional[TreeNode]) -> List[List[int]]:
while not root:
return []
queue = [root]
result = []
while queue:
level_nodes = []
temp = []
for node in queue:
level_nodes.append(node.val)
if node.left:
temp.append(node.left)
if node.right:
temp.a bppend(node.right)
queue = temp
result.append(level_nodes)
return result
# 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 pathSum(self, root: TreeNode, targetSum: int) -> List[List[int]]:
self.resultpath = []
def dfs(node,target,temp):
if node is None:
return
temp.append(node.val)
print(temp)
if node.left is None and node.right is None and target == node.val:
self.resultpath.append(temp)
dfs(node.left, target-node.val, temp)
dfs(node.right, target-node.val, temp)
dfs(root, targetSum, [])
return self.resultpath
this is really confusing me. For a "Input: root = [5,4,8,11,null,13,4,7,2,null,null,5,1], targetSum = 22"
picture of the tree: https://imgur.com/a/cAK8kQn
As this code goes through the recursions, at temp = [5,4,11], dfs(node.left ...) will turn this into [5,4,11,7] but temp is still [5,4,11], so dfs(node.right ...) should turn this into [5,4,11,2] but the 7 from dfs(node.left ...) shows up to make it [5,4,11,7,2].
Why is that? How would I fix this code so it doesn't do that?
The issue is quite simple. There is only a single temp. You are passing a reference to this single object in all recursive calls, so any mutations in a recursive call to dfs will be visible from the calling scope.
The key is to simply copy temp every time you make a recursive call.
For a binary tree, we can traverse it in one line just like this (inorder, preorder, postorder is all ok):
# 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
# this is a preorder traversal with one line:
class Solution:
def preorderTraversal(self, root) -> List[int]:
return [] if root is None else [r.val] + self.preorderTraversal(r.left) + self.preorderTraversal(r.right)
For a tree that has multi-child in its node, how to complete the traversal work in one line?
I think list comprehension is a possible method, but I cannot complete the work in one line.
"""
# Definition for a Node.
class Node:
def __init__(self, val=None, children=None):
self.val = val
self.children = children
"""
class Solution:
def preorder(self, root: 'Node') -> List[int]:
if root is None: return []
ans = [root.val]
[ans.extend(x) for x in [self.preorder(child) for child in root.children]]
return ans
# This is a normal traversal:
# class Solution:
# def preorder(self, root: 'Node') -> List[int]:
# if root is None: return []
# ans = [root.val]
# for child in root.children:
# ans += self.preorder(child)
# return ans
Use a list comprehension to gather the traversal of all the root's children, regardless of how many children there are.
class Solution:
def preorderTraversal(self, root) -> List[int]:
# Original hard-coded approach for binary trees
# return [] if root is None else [r.val] \
# + self.preorderTraversal(root.left) + self.preorderTraversal(root.right)
# Generalized approach for binary trees
# return [] if root is None else [r.val] \
# + [y for child in [root.left, root.right] for y in self.preorderTraversal(child)]
# Generalized approach for a tree with arbitrary children per node
return [] if root is None else ([root.val]
+ [y for child in root.children for y in self.preorderTraversal(child)])
It could work like this:
class Solution:
def preorder(self, root):
return [] if root is None else [root.val] + [value
for child in (root.children or [])
for value in self.preorder(child)]
The idea is that list comprehension replaces a repeated call to append, not to extend. The non-comprehension code, that maps to the above list comprehension version, is:
class Solution:
def preorder(self, root):
if root is None:
return []
res = [root.val]
for child in (root.children or []):
for value in self.preorder(child):
res.append(value)
return res
I am trying to do the zigzag level order traversal of a binary tree's nodes values (ie, from left to right, then right to left for the next level and alternate between) on https://www.interviewbit.com/problems/zigzag-level-order-traversal-bt/ But the compiler gives time limit exceeded error. How can I resolve it?
# Definition for a binary tree node
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
# #param A : root node of tree
# #return a list of list of integers
def zigzagLevelOrder(self, A):
st_crt_lvl =[A]
st_nxt_lvl =[]
ans_list = []
while st_crt_lvl:
u = st_crt_lvl.pop(0)
ans_list.append(u.val)
if u.left:
st_nxt_lvl.append(u.left)
if u.right:
st_nxt_lvl.append(u.right)
while st_nxt_lvl:
u = st_nxt_lvl.pop()
ans_list.append(u.val)
if u.right:
st_crt_lvl.append(u.right)
if u.left:
st_crt_lvl.append(u.left)
return ans_list
You can eliminate multiple inner while loops from your code, by making the queue st_nxt_lvl temporary and copying the content of this temporary queue to the current one st_crt_lvl at the end processing of each level of the binary tree.
This could be achieved by keeping just a single queue (without any temporary storage) and level order traversal by standard bfs algorithm, but since we want zig-zag order traversal at each level, it's more elegant to have a temporary queue, so that the temporary queue only keeps the next level elements and when processing of the current level elements is done, the current queue points to the next level.
With some modification of your code, along with an example tree:
def zigzagLevelOrder(A):
st_crt_lvl = [A] # initialize
ans_list = []
level = 0
while st_crt_lvl: # check if all levels are processed
st_nxt_lvl =[] # temporary queue to hold the next level elements
tmp = [] # temporary storage to append to the ans_list
while st_crt_lvl:
u = st_crt_lvl.pop(0)
tmp.append(u.val)
if u.left:
st_nxt_lvl.append(u.left)
if u.right:
st_nxt_lvl.append(u.right)
if (len(tmp) > 0): # if tmp is not empty
if level % 2 == 1: # ensure zig-zag level order traversal
tmp = tmp[::-1]
ans_list.append(tmp)
st_crt_lvl = st_nxt_lvl # copy the temporary queue to the current queue
level += 1
return ans_list
class BinaryTree:
def __init__(self, left, right, data):
self.left = left
self.right = right
self.val = data
A = BinaryTree(None, None, 3)
A.left = BinaryTree(None, None, 9)
A.right = BinaryTree(None, None, 20)
A.left.left = BinaryTree(None, None, 1)
A.left.right = BinaryTree(None, None, 2)
A.right.left = BinaryTree(None, None, 15)
A.right.right = BinaryTree(None, None, 7)
zigzagLevelOrder(A)
# [[3], [20, 9], [1, 2, 15, 7]]
You can use a breadth-first search:
from collections import deque, defaultdict
class Tree:
def __init__(self, **kwargs):
self.__dict__ = {i:kwargs.get(i) for i in ['left', 'right', 'value']}
def __contains__(self, _val):
if self.value != _val and self.left is None and self.right is None:
return False
return True if self.value == _val else any([_val in [[], self.left][self.left is not None], _val in [[], self.right][self.right is not None]])
def __lookup(self, _val, _depth = 0):
if self.value == _val:
return _depth
return getattr(self, 'left' if _val in self.left else 'right').__lookup(_val, _depth+1)
def __getitem__(self, _val):
return self.__lookup(_val)
def bfs(_head):
_d = deque([_head])
_seen = []
_last = None
_final_result = defaultdict(list)
while _d:
_current = _d.popleft()
if _current.value not in _seen:
_seen.append(_current.value)
_r = list(filter(None, [getattr(_current, i, None) for i in ['left', 'right']]))
_d.extend(_r)
_final_result[_head[_current.value]].append(_current.value)
marker = iter(range(len(_final_result)))
return [i[::-1] if next(marker)%2 else i for _, i in sorted(_final_result.items(), key=lambda x:x[0])]
When constructing the same tree in the example from the link in the question, the output is:
t = Tree(value=3, left=Tree(value=9), right=Tree(value=20, left=Tree(value=15), right=Tree(value=7)))
print(bfs(t))
Output:
[[3], [20, 9], [15, 7]]
This solution uses the breadth-first search to traverse the tree horizontally. However, since a (complete) binary tree has two children, only two values will be added to the queue. Therefore, in order to determine the current tree level the search has reached, a method to find the depth of a particular value has to be implemented in the tree (__getitem__ and __lookup).
I am playing around with some toy code in Python. But somehow cant get through. I am using a recursion in a Tree data structure to generate paths from a particular node to each children leaf nodes.
The idea behind the recursive function is to have a list which would collect each path to the individual leaf node and then collect each paths in another list.
class Tree:
def __init__(self):
self._ancestors = []
self._store_nodes = {}
def add_node(self, node):
assert isinstance(node, Node)
self._store_nodes[node.name] = node
def get_c_path(self, node):
subpath = []
path = []
path = self.ret_path(node, subpath, path)
return path
## recursive function to fetch paths
def ret_path(self, node, subpath=[], pathstore=[]):
if len(node.children) == 0:
pathstore.append(subpath)
return
else:
for c in node.children:
subpath.append(c)
self.ret_path(c, subpath, pathstore)
class Node(object):
def __init__(self, name=''):
self._name = name
self._children = set([])
self._parents = set([])
#property
def name(self):
return self._name
#property
def children(self):
return self._children
#property
def parents(self):
return self._parents
def add_child(self, node):
assert isinstance(node, Node)
self._children.add(node)
def add_parent(self, node):
assert isinstance(node, Node)
self._parents.add(node)
if __name__ == '__main__':
node_store = {1 : [2,3,4,5,6], 6 : [7,2,8,9,5], 2 : [10,11,5], 12 : [13,14,15,16], 5 : [21,22,23]}
tree = Tree()
## build the tree and set parents and children of each node
for k, v in node_store.items():
parent_node = None
if k in tree._store_nodes:
parent_node = tree._store_nodes[k]
else:
parent_node = Node(k)
tree.add_node(parent_node)
for c in v:
child_node = None
if c in tree._store_nodes:
child_node = tree._store_nodes[c]
else:
child_node = Node(c)
tree.add_node(child_node)
parent_node.add_child(child_node)
child_node.add_parent(parent_node)
print '-------------'
path = tree.get_c_path(tree._store_nodes[2])
for p in path:
for t in p:
print t.name
print "-----"
The result I am expecting is a list of list for Node-2 as follows:
path = [[10], [11], [5, 21], [5, 22], [5, 23]]
How can I correct my recursive function?
Here's two methods that would accomplish this goal. I'm not quite sure how to fix your structure; it seemed easier to start from scratch.
def get_c_path(self, node):
branches = [[c] for c in node.children]
expanded = self.expand_branches(branches)
while branches != expanded:
branches = expanded
expanded = self.expand_branches(expanded)
return expanded
def expand_branches(self, branches):
new_branches = []
for branch in branches:
last_node = branch[-1]
if last_node.children:
for child in last_node.children:
new_branches.append(branch + [child])
else:
new_branches.append(branch)
return new_branches