How to list the longest path in binary tree? - python
Here we are trying to list the longest path in a binary tree. For instance,
list_longest_path(None)
[]
list_longest_path(BinaryTree(5))
[5]
b1 = BinaryTree(7)
b2 = BinaryTree(3, BinaryTree(2), None)
b3 = BinaryTree(5, b2, b1)
list_longest_path(b3)
[5, 3, 2]
My code is at bottom. Apparently the code returns every node in the tree. Here I am having difficulty on how to generate all lists while using max()at the same time?
class BinaryTree:
"""
A Binary Tree, i.e. arity 2.
=== Attributes ===
#param object data: data for this binary tree node
#param BinaryTree|None left: left child of this binary tree node
#param BinaryTree|None right: right child of this binary tree node
"""
def __init__(self, data, left=None, right=None):
"""
Create BinaryTree self with data and children left and right.
#param BinaryTree self: this binary tree
#param object data: data of this node
#param BinaryTree|None left: left child
#param BinaryTree|None right: right child
#rtype: None
"""
self.data, self.left, self.right = data, left, right
def __eq__(self, other):
"""
Return whether BinaryTree self is equivalent to other.
#param BinaryTree self: this binary tree
#param Any other: object to check equivalence to self
#rtype: bool
>>> BinaryTree(7).__eq__("seven")
False
>>> b1 = BinaryTree(7, BinaryTree(5))
>>> b1.__eq__(BinaryTree(7, BinaryTree(5), None))
True
"""
return (type(self) == type(other) and
self.data == other.data and
(self.left, self.right) == (other.left, other.right))
def __repr__(self):
"""
Represent BinaryTree (self) as a string that can be evaluated to
produce an equivalent BinaryTree.
#param BinaryTree self: this binary tree
#rtype: str
>>> BinaryTree(1, BinaryTree(2), BinaryTree(3))
BinaryTree(1, BinaryTree(2, None, None), BinaryTree(3, None, None))
"""
return "BinaryTree({}, {}, {})".format(repr(self.data),
repr(self.left),
repr(self.right))
def __str__(self, indent=""):
"""
Return a user-friendly string representing BinaryTree (self)
inorder. Indent by indent.
>>> b = BinaryTree(1, BinaryTree(2, BinaryTree(3)), BinaryTree(4))
>>> print(b)
4
1
2
3
<BLANKLINE>
"""
right_tree = (self.right.__str__(
indent + " ") if self.right else "")
left_tree = self.left.__str__(indent + " ") if self.left else ""
return (right_tree + "{}{}\n".format(indent, str(self.data)) +
left_tree)
def __contains__(self, value):
"""
Return whether tree rooted at node contains value.
#param BinaryTree self: binary tree to search for value
#param object value: value to search for
#rtype: bool
>>> BinaryTree(5, BinaryTree(7), BinaryTree(9)).__contains__(7)
True
"""
return (self.data == value or
(self.left and value in self.left) or
(self.right and value in self.right))
def list_longest_path(node):
"""
List the data in a longest path of node.
#param BinaryTree|None node: tree to list longest path of
#rtype: list[object]
>>> list_longest_path(None)
[]
>>> list_longest_path(BinaryTree(5))
[5]
>>> b1 = BinaryTree(7)
>>> b2 = BinaryTree(3, BinaryTree(2), None)
>>> b3 = BinaryTree(5, b2, b1)
>>> list_longest_path(b3)
[5, 3, 2]
"""
if node is None:
return []
elif not node.left and not node.right:
return [node]
else:
return [node]+list_longest_path(node.left)+list_longest_path(node.right)
The longest path in a tree, is called "diameter". So you are looking for something like a "python tree diameter calculator".
You can see the implementation of the algorithm here:
http://www.geeksforgeeks.org/diameter-of-a-binary-tree/
and here:
http://tech-queries.blogspot.com.br/2010/09/diameter-of-tree-in-on.html
Since this website contains only code in C and JAVA, you could take a look here to get some pythonic coding ideas:
Optimize finding diameter of binary tree in Python
Here's a Python function that will return the path:
def list_longest_path(root):
if not root:
return []
l = list_longest_path(root.left)
r = list_longest_path(root.right)
if len(l) > len(r):
return [root] + l
else:
return [root] + r
In your code there's no need to check if left or right child exists since
your function will return list in any case. What you need to do though is
to check the length of the lists returned from children an pick the one
that is longer.
Related
Find matrix row elements in a binary tree
I am trying to write a function which given a binary search tree T of integers and a rectangular matrix M of integers, verify if there exists a row of M whose values belong to T. This is my code: M = [ [1, 2, 3], [4, 5, 6] ] class Tree: def __init__(self, root=None, left=None, right=None): self.root = root self.left = left self.rigth = right def FindRowInTree(T, M): if T is None: return False else: for r in M: for e in r: if e == T.root and FindRowInTree(T.left, M) is True and FindRowInTree(T.right, M) is True: return True FindRowInTree(T.left, M) and FindRowInTree(T.right,M) return False t = Tree(4, Tree(5, None, None), Tree(6, None, None)) x = FindRowInTree(t, M) print(x) It always returns False. What would I need to change to make it work properly?
Break the problem into pieces. First write a function to find a single value in the tree: class Tree: def __init__(self, root=None, left=None, right=None): self.root = root self.left = left self.right = right def __contains__(self, value): return ( self.root == value or self.left is not None and value in self.left or self.right is not None and value in self.right ) Note that with an ordered binary tree, you could make this function more efficient by having it only check left or right depending on how the value you're looking for compares to the root value; that's what a "binary search" is. Since your tree is unordered, though, you just need to search both children at each node, meaning you're traversing the entire tree. In any case, once you have a function that looks up a single value, all you need to do is call it in a loop: def find_row_in_tree(tree, matrix): return any( all(i in tree for i in row) for row in matrix ) If you're trying to do this in a more efficient way, an unordered binary tree is not doing you any favors; I'd just write a utility function to convert it to something more useful, like a set: def tree_to_set(tree): if tree is None: return set() return {tree.root} | tree_to_set(tree.left) | tree_to_set(tree.right) def find_row_in_tree(tree, matrix): tree_as_set = tree_to_set(tree) return any(tree_as_set.issuperset(row) for row in matrix)
Leetcode Same Tree
I'm trying to solve same tree from leetcode with python. original problem. https://leetcode.com/problems/same-tree/ My code was able to pass a few test cases but not all. It couldn't pass the submission. My idea is to flatten the tree and compare the two lists. The failed case is at the bottom of the code. # Definition for a binary tree node. # class TreeNode(object): # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution(object): def isSameTree(self, p, q): """ :type p: TreeNode :type q: TreeNode :rtype: bool """ def flatten(root): if root is None: return ["null"] if root.left is None and root.right is None: return [root.val] if root.left is None: # print 'left', [root.val, "null", flatten(root.right)] return [root.val, "null", flatten(root.right)] if root.right is None: # print 'right', [root.val, flatten(root.left), "null"] return [root.val, flatten(root.left), "null"] else: # print flatten(root.right) + flatten(root.right) return flatten(root.right) + flatten(root.right) return flatten(p) == flatten(q) ## Failed test case ## [390,255,2266,-273,337,1105,3440,-425,4113,null,null,600,1355,3241,4731,-488,-367,16,null,565,780,1311,1755,3075,3392,4725,4817,null,null,null,null,-187,152,395,null,728,977,1270,null,1611,1786,2991,3175,3286,null,164,null,null,4864,-252,-95,82,null,391,469,638,769,862,1045,1138,null,1460,1663,null,1838,2891,null,null,null,null,3296,3670,4381,null,4905,null,null,null,-58,null,null,null,null,null,null,null,null,734,null,843,958,null,null,null,1163,1445,1533,null,null,null,2111,2792,null,null,null,3493,3933,4302,4488,null,null,null,null,null,null,819,null,null,null,null,1216,null,null,1522,null,1889,2238,2558,2832,null,3519,3848,4090,4165,null,4404,4630,null,null,null,null,null,null,1885,2018,2199,null,2364,2678,null,null,null,3618,3751,null,4006,null,null,4246,null,null,4554,null,null,null,1936,null,null,null,null,2444,2642,2732,null,null,null,null,null,null,null,4253,null,null,null,null,2393,2461,null,null,null,null,4250,null,null,null,null,2537] ## [390,255,2266,-273,337,1105,3440,-425,4113,null,null,600,1355,3241,4731,-488,-367,16,null,565,780,1311,1755,3075,3392,4725,4817,null,null,null,null,-187,152,395,null,728,977,1270,null,1611,1786,2991,3175,3286,null,164,null,null,4864,-252,-95,82,null,391,469,638,769,862,1045,1138,null,1460,1663,null,1838,2891,null,null,null,null,3296,3670,4381,null,4905,null,null,null,-58,null,null,null,null,null,null,null,null,734,null,843,958,null,null,null,1163,1445,1533,null,null,null,2111,2792,null,null,null,3493,3933,4302,4488,null,null,null,null,null,null,819,null,null,null,null,1216,null,null,1522,null,1889,2238,2558,2832,null,3519,3848,4090,4165,null,4404,4630,null,null,null,null,null,null,1885,2018,2199,null,2364,2678,null,null,null,3618,3751,null,4006,null,null,4246,null,null,4554,null,null,null,1936,null,null,null,null,2444,2642,2732,null,null,null,null,null,null,null,4253,null,null,null,null,2461,2393,null,null,null,null,4250,null,null,null,null,2537]
To determine if two trees are identical, you need to determine that the structure is the same i.e equal nodes at the same level and branch. You can write a recursive function that loops over the tree and creates a Huffman encoding, which can later be used to compare the nodes: class Solution(object): #classmethod def tree_paths(cls, _tree:TreeNode, _paths = []): yield [_tree.val, _paths] if _tree.left is not None: yield from cls.tree_paths(_tree.left, _paths+[0]) if _tree.right is not None: yield from cls.tree_paths(_tree.right, _paths+[1]) def isSameTree(self, p, q): if p is None and q is None: return True if not all([p, q]): return False _tree1, _tree2 = list(self.__class__.tree_paths(p)), list(self.__class__.tree_paths(q)) if len(_tree1) != len(_tree2): return False return all(a == b and all(c ==d for c, d in zip(j, l)) for [a, j], [b, l] in zip(_tree1, _tree2)) To test, a tree with the same attributes as the original TreeNode can be created: class TreeNode: def __init__(self, **kwargs:dict) -> None: self.__dict__ = {i:kwargs.get(i) for i in ['val', 'left', 'right']} t1 = TreeNode(val=1, left=TreeNode(val=2), right=TreeNode(val=3)) t2 = TreeNode(val=1, left=TreeNode(val=2), right=TreeNode(val=3)) t3 = TreeNode(val=1, left=TreeNode(val=2), right=TreeNode(val=4)) print(Solution().isSameTree(t1, t2)) print(Solution().isSameTree(t1, t3)) Output: True False This answer was successfully accepted on LeetCode. Edit: Your code is close, however, flatten(root.right) + flatten(root.right) must be changed, as you are finding the path of nodes on the right subtree twice. Also, you have to include the value of the current tree instance passed to isSameTree. Thus, flatten(root.right) + flatten(root.right) must become: return flatten(root.left)+[root.val]+flatten(root.right)
How do I traverse binary tree made up of nodes? (code inside)
I am given a class that creates a binary tree filled with nodes.each node is given a parent and a pointer to its left or right child. Binary tree node class: class BTNode(): ''' a class that represents a binary tree node''' def __init__(self, data, parent=None, left_child=None, right_child=None): '''(BTNode, obj, BTNode, BTNode, BTNode) -> NoneType Constructs a binary tree nodes with the given data''' self._parent = parent self._left = left_child self._data = data self._right = right_child def set_parent(self, parent): '''(BTNode, BTNode) -> NoneType set the parent to the given node''' self._parent = parent def set_left(self, left_child): '''(BTNode, BTNode) -> NoneType set the left child to the given node''' self._left = left_child def set_right(self, right_child): '''(BTNode, BTNode) -> NoneType set the right child to the given node''' self._right = right_child def set_data(self, data): '''(BTNode, obj) -> NoneType set the data at this node to the given data''' self._data = data def get_parent(self): '''(BTNode) -> BTNode return the pointer to the parent of this node''' return self._parent def get_left(self): '''(BTNode) -> BTNode return the pointer to the left child''' return self._left def get_right(self): '''(BTNode) -> BTNode return the pointer to the right child''' return self._right def get_data(self): '''(BTNode) -> obj return the data stored in this node''' return self._data def has_left(self): '''(BTNode) -> bool returns true if this node has a left child''' return (self.get_left() is not None) def has_right(self): '''(BTNode) -> bool returns true if this node has a right child''' return (self.get_right() is not None) def is_left(self): '''(BTNode) -> bool returns true if this node is a left child of its parent''' # you need to take care of exception here, if the given node has not parent return (self.get_parent().get_left() is self) def is_right(self): '''(BTNode) -> bool returns true if the given node is a right child of its parent''' # you need to take care of exception here, if the given node has not parent return (self.get_parent().get_right() is self) def is_root(self): '''(BTNode) -> bool returns true if the given node has not parent i.e. a root ''' return (self.get_parent() is None) code example of how to create a tree: ''' create this BT using BTNode A / \ B C /\ \ D E F / G ''' node_G = BTNode("G") node_F = BTNode("F", None,node_G) node_G.set_parent(node_F) node_C = BTNode("C", None, None, node_F) node_F.set_parent(node_C) node_D = BTNode("D") node_E = BTNode("E") node_B = BTNode("B",None, node_D, node_E) node_D.set_parent(node_B) node_E.set_parent(node_B) node_A = BTNode("A",None, node_B, node_C) node_B.set_parent(node_A) I dont know how to traverse this tree. I was suggested using recursion but Im not sure how. For example, I need to return True if the tree differs in height by at most 1 level,so the tree above would return true. How do I do this? Thanks!
Try to think recursively. Let's start off with a few definitions. A tree is balanced if its left and right trees have the same height and each of it's subtrees is balanced. Also we will define an empty tree as being balanced. The height of a tree, h(t) = 1 + max(h(t.left), h(t.right)). In English, the height of a tree is 1 + the height of its taller child tree. Also we will assume that an empty tree has a height of 0. So for every node in the tree we can check the height of both of its children and compare them. If they aren't equal we know the tree is not balanced and we return false. Let's start by defining the code to check if a tree is balanced. def is_balanced(node): if node is None: return True left_height = get_height(node.get_left()) right_height = get_height(node.get_right()) return left_height == right_height and is_balanced(node.get_left()) and is_balanced(node.get_right()) Now let's define the function get_height that we used above. Since the height of a tree is a function of a height of it's subtrees we can use recursion. Since recursion requires a base case so we do not recurse infinitely we can use the fact that an empty tree has a height of 0. def get_height(node): if node is None: return 0 # Assuming empty tree has a height of 0 return 1 + max(get_height(node.get_left()), get_height(node.get_right())) Now to put it all together we can recursively iterate through the tree and check that every node is balanced by calling is_balanced on the root. is_balanced(node_A) BONUS Exercise: The code I gave you will work but it won't scale well. If the tree gets very large it will run much slower. Why is it slow and what can you do to make it faster?
You can traverse the left and right sides of the tree to find the maximum path length to a leaf: class Tree: def __init__(self, **kwargs): self.__dict__ = {i:kwargs.get(i) for i in ['value', 'left', 'right']} def get_length(self, current=[]): yield current+[1] yield from getattr(self.left, 'get_length', lambda _:[])(current+[1]) yield from getattr(self.right, 'get_length', lambda _:[])(current+[1]) def right_length(self): return len(max(getattr(self.right, 'get_length', lambda :[[]])(), key=len)) def left_length(self): return len(max(getattr(self.left, 'get_length', lambda :[[]])(), key=len)) t = Tree(value = 'A', left=Tree(value='B', left=Tree(value='D'), right=Tree(value='E')), right = Tree(value='C', left = Tree(value='F', left=Tree(value='G')))) print(t.right_length() - t.left_length()) Output: 1
How to write parentheses for binary tree?
Here I am trying to combine the binary tree into expression. For instance b1 = BinaryTree(3.0) print(parenthesize(b1)) 3.0 b2 = BinaryTree(4.0) b3 = BinaryTree(7.0) b4 = BinaryTree("*", b1, b2) b5 = BinaryTree("+", b4, b3) print(parenthesize(b5))` ((3.0 * 4.0) + 7.0) The code I write for parenthesize() is at the bottom and the above are the Binary tree base code. But my code, instead of returning "somenumber", it returns ("somenumber"). When I delete the "(", the parenthesizes totally disappeared. Could someone help fill the code? class BinaryTree: """ A Binary Tree, i.e. arity 2. === Attributes === #param object data: data for this binary tree node #param BinaryTree|None left: left child of this binary tree node #param BinaryTree|None right: right child of this binary tree node """ def __init__(self, data, left=None, right=None): """ Create BinaryTree self with data and children left and right. #param BinaryTree self: this binary tree #param object data: data of this node #param BinaryTree|None left: left child #param BinaryTree|None right: right child #rtype: None """ self.data, self.left, self.right = data, left, right def __eq__(self, other): """ Return whether BinaryTree self is equivalent to other. #param BinaryTree self: this binary tree #param Any other: object to check equivalence to self #rtype: bool >>> BinaryTree(7).__eq__("seven") False >>> b1 = BinaryTree(7, BinaryTree(5)) >>> b1.__eq__(BinaryTree(7, BinaryTree(5), None)) True """ return (type(self) == type(other) and self.data == other.data and (self.left, self.right) == (other.left, other.right)) def __repr__(self): """ Represent BinaryTree (self) as a string that can be evaluated to produce an equivalent BinaryTree. #param BinaryTree self: this binary tree #rtype: str >>> BinaryTree(1, BinaryTree(2), BinaryTree(3)) BinaryTree(1, BinaryTree(2, None, None), BinaryTree(3, None, None)) """ return "BinaryTree({}, {}, {})".format(repr(self.data), repr(self.left), repr(self.right)) def __str__(self, indent=""): """ Return a user-friendly string representing BinaryTree (self) inorder. Indent by indent. >>> b = BinaryTree(1, BinaryTree(2, BinaryTree(3)), BinaryTree(4)) >>> print(b) 4 1 2 3 <BLANKLINE> """ right_tree = (self.right.__str__( indent + " ") if self.right else "") left_tree = self.left.__str__(indent + " ") if self.left else "" return (right_tree + "{}{}\n".format(indent, str(self.data)) + left_tree) def __contains__(self, value): """ Return whether tree rooted at node contains value. #param BinaryTree self: binary tree to search for value #param object value: value to search for #rtype: bool >>> BinaryTree(5, BinaryTree(7), BinaryTree(9)).__contains__(7) True """ return (self.data == value or (self.left and value in self.left) or (self.right and value in self.right)) def parenthesize(b): """ Return a parenthesized expression equivalent to the arithmetic expression tree rooted at b. Assume: -- b is a binary tree -- interior nodes contain data in {'+', '-', '*', '/'} -- interior nodes always have two children -- leaves contain float data #param BinaryTree b: arithmetic expression tree #rtype: str >>> b1 = BinaryTree(3.0) >>> print(parenthesize(b1)) 3.0 >>> b2 = BinaryTree(4.0) >>> b3 = BinaryTree(7.0) >>> b4 = BinaryTree("*", b1, b2) >>> b5 = BinaryTree("+", b4, b3) >>> print(parenthesize(b5)) ((3.0 * 4.0) + 7.0) """ if b is None: return '' else: return "("+parenthesize(b.left)+str(b.data)+parenthesize(b.right)+")"
It seems that you want your code to only place parentheses around nodes (trees) that have operations attached. In your comments you say that b1 = BinaryTree(3.0) print(parenthesize(b1)) # 3.0 But that isn't what is happening when you run your code. Instead the output is (3.0) this is introducing redundant parentheses when your node is part of a larger expression. To correct the issue I added an elif clause to your function as shown below. def parenthesize(b): if b is None: return '' elif b.left is None and b.right is None: return str(b.data) else: return "("+ parenthesize(b.left)+str(b.data) + parenthesize(b.right)+") This produces the following output: b1 = BinaryTree(3.0) b2 = BinaryTree(4.0) b3 = BinaryTree(7.0) b4 = BinaryTree("*", b1, b2) b5 = BinaryTree("+", b4, b3) print(parenthesize(b5)) # ((3.0*4.0)+7.0) Which I think is what you want. You may want to change the elif clause to check for only a single side being empty as opposed to both, but I don't know how you are going to use your code. For example, do you want a unary expression such as 3++ to be allowed? and if so do you want to enclose it in ()?
Python: Build Binary Tree with Pre and Inorder
I need help completing the recursive part of my function. The function is supposed to use my ListBinaryTree Class to help reconstruct a tree given its inorder and preorder traversal in string format: eg. preorder = '1234567' inorder = '3241657' def build_tree(inorder, preorder): head = preorder[0] print(head) head_pos = inorder.index(head) print(head_pos) left_in = inorder[:head_pos] print(left_in) right_in = inorder[(head_pos+1):] print(right_in) left_pre = preorder[1:-len(right_in)] print(left_pre) right_pre = preorder[-len(right_in):] print(right_pre) Which finds the important values in the preorder and inorder traversals and splits the tree up to determine which numbers are for the left side and right side of the tree. An example of its input and output is: build_tree('3241657', '1234567') . 1 3 324 657 234 567 My class that I use to create the tree is as follows: class ListBinaryTree: """A binary tree class with nodes as lists.""" DATA = 0 # just some constants for readability LEFT = 1 RIGHT = 2 def __init__(self, root_value, left=None, right=None): """Create a binary tree with a given root value left, right the left, right subtrees """ self.node = [root_value, left, right] def create_tree(self, a_list): return ListBinaryTree(a_list[0], a_list[1], a_list[2]) def insert_value_left(self, value): """Inserts value to the left of this node. Pushes any existing left subtree down as the left child of the new node. """ self.node[self.LEFT] = ListBinaryTree(value, self.node[self.LEFT], None) def insert_value_right(self, value): """Inserts value to the right of this node. Pushes any existing left subtree down as the left child of the new node. """ self.node[self.RIGHT] = ListBinaryTree(value, None, self.node[self.RIGHT]) def insert_tree_left(self, tree): """Inserts new left subtree of current node""" self.node[self.LEFT] = tree def insert_tree_right(self, tree): """Inserts new left subtree of current node""" self.node[self.RIGHT] = tree def set_value(self, new_value): """Sets the value of the node.""" self.node[self.DATA] = new_value def get_value(self): """Gets the value of the node.""" return self.node[self.DATA] def get_left_subtree(self): """Gets the left subtree of the node.""" return self.node[self.LEFT] def get_right_subtree(self): """Gets the right subtree of the node.""" return self.node[self.RIGHT] def __str__(self): return '['+str(self.node[self.DATA])+', '+str(self.node[self.LEFT])+', '+\ str(self.node[self.RIGHT])+']' For the recursive part of the function I tried doing something like: my_tree= ListBinaryTree(head) while my_tree.get_value() != None: left_tree = build_tree(left_in, left_pre) right_tree = build_tree(right_in, right_pre) my_tree.insert_value_left(left_tree) my_tree.insert_value_right(right_tree) print (my_tree) But it returns an "index out of range" error. Also for something like: def build_tree(inorder, preorder): head = preorder[0] head_pos = inorder.index(head) left_in = inorder[:head_pos] right_in = inorder[(head_pos+1):] left_pre = preorder[1:-len(right_in)] right_pre = preorder[-len(right_in):] if left_in: left_tree = build_tree(left_in, left_pre) else: left_tree = None if right_in: right_tree = build_tree(right_in, right_pre) else: right_tree = None my_tree = ListBinaryTree(head, left_tree, right_tree) print(my_tree) input build_tree('3241657', '1234567') returns [3, None, None] [4, None, None] [2, None, None] [6, None, None] [7, None, None] [5, None, None] [1, None, None] Can anyone please help me with the recursive part? Thanks
You're making the recursive part much harder than necessary. if left_in: left_tree = build_tree(left_in, left_pre) else: left_tree = None if right_in: right_tree = build_tree(right_in, right_pre) else: right_tree = None return ListBinaryTree(head, left_tree, right_tree) You could perhaps simplify it even further by moving the checks for empty sequences up to the top of the function (e.g. if not inorder: return None) so it only needs to appear once.