Python - append list to other list? - python

Leetcode 113 - Path Sum II
Given the root of a binary tree and an integer targetSum, return all root-to-leaf paths where each path's sum equals targetSum.
# 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]]:
if not root: return []
res = []
def dfs(node, total = 0, path = []):
if not node: return
path.append(node.val)
total += node.val
if not node.left and not node.right and total == targetSum:
res.append(list(path))
else:
dfs(node.left, total, path)
dfs(node.right, total, path)
total -= path.pop()
dfs(root)
return res
Why we have to use res.append(list(path)) rather than use res.append(path)?
If we only append path into res, it would only append empty list into res.

This is a subtle Python issue. When you use a default parameter like that (in the def dfs line), it captures that default object at definition time. So, every time that function runs, path is set to the SAME empty list. If you change that list, everyone with a reference to it sees the change. I believe they use list(path) to make a copy of that list, rather than store a link to the common list.

Related

Understanding overriding in in-order tree traversal

I am looking to return the k-th element of a binary tree and came up with this solution:
# 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 kthSmallest(self, root: Optional[TreeNode], k: int) -> int:
if not root:
return None
out = []
return self.Search(root,k,out)[k-1]
def Search(self,root,k,out):
if root:
# iterate over the tree using DFS, and after the last iteration return the sorted list "out"
self.Search(root.left,k,out)
self.Search(root.right,k,out)
out.append(root.val)
return sorted(out)
My question is: Why can't I return sorted(out)[k-1] in the Search method? I have to return the sorted list to the kthSmallest method and then search for the k-th entry and I don't understand why.

Recursive DFS Function not returning every Root to Leaf Path

I am currently trying to make a list of lists with all of the root to leaf paths in a binary tree. When I try writing out the result for the paths list and all of the recursive calls I can't seem to figure out where the error would lie. I thought of the idea of popping off of each individual path after hitting a leaf but that gave weird results as well. I also include the definition of the Tree Node which is the format for the input.
Current input: [1,2,3,null,5](1 is root, 2 and 3 are children of 1, and 5 is the right child of 2)
Expected output: [[1,2,3],[1,3]]
Current output: [[1,2,5,3],[1,2,5,3]]
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
def binaryTreePaths(self, root: Optional[TreeNode]):
if not root:
return
paths = []
def traverse(root,path,paths):
if not root:
return []
path.append(root.val)
if not root.left and not root.right:
paths.append(path)
traverse(root.left,path,paths)
traverse(root.right,path,paths)
traverse(root,[],paths)
return paths
If I'm not mistaken, you are doing this LC question. https://leetcode.com/problems/binary-tree-paths/
I have solved this question on LC, so pasting the modified version with comments.
def binaryTreePaths(self, root: Optional[TreeNode]) -> List[str]:
# for empty root, return empty array
if not root:
return []
# variable to hold all paths
paths = []
def traverse(root,path,paths):
if not root:
return
# if root(node) is not empty, this node value will need to be added in current path
path.append(root.val)
# if the above node is leaf node,
# we have to make a copy of path (since list are mutable)
# and then pop the element of this current path as we back track
if not root.left and not root.right:
paths.append(path[:])
path.pop()
return
# if above node was not leaf node, then travese right and left
traverse(root.left,path,paths)
traverse(root.right,path,paths)
# once traversed, we backtrack by popping
path.pop()
traverse(root,[],paths)
return paths

Binary Search Tree insert function failing to add a new node to the tree

I'm writing code to implement a Binary Search Tree in Python. I ran into problems in writing the insert function, which should add a new node at the correct in order location in the tree. I wrote it in two different ways: insertNode1 works fine (correctly performs an insert on the tree), but insertNode2 does not perform the insertion properly. When I Do InOrderTraversal for the tree using insertNode1 and insertNode2, it turned out that the 'insertNode1' yields the full tree while the 'insertNode2' only yields the root.
Why is it that insertNode1 succeeds while insertNode2 fails, and what are the meaningful differences between the two functions that cause this to be the case?
Here's my code:
def insert(self,val):
if not self.root:
self.root = TreeNode(val)
else:
self.insertNode2(self.root, val)
def insertNode1(self,node, val):
if val < node.val:
if not node.left:
node.left = TreeNode(val)
else:
self.insertNode1(node.left,val)
else:
if not node.right:
node.right = TreeNode(val)
else:
self.insertNode1(node.right, val)
def insertNode2(self, node, val):
if not node:
node = TreeNode(val)
else:
if node.val > val:
self.insertNode2(node.left, val)
else:
self.insertNode2(node.right, val)
insertNode2 doesn't correctly perform an insertion as expected because of the line node = TreeNode(val), which makes a purely local assignment to node. This new object is never set to its parent .left or .right property and is lost when the function returns. The root node will not be modified in any run of this function.
Either use the already-working insertNode1, or add a return node statement to insertNode2 and make an assignment in the parent function call scope to the new child.
Here's a snippet demonstrating how that might be done:
class TreeNode:
def __init__(self, val, left=None, right=None):
self.val = val
self.left = left
self.right = right
class BinarySearchTree:
#staticmethod
def p(root, depth=0):
if root:
print(" " * depth + str(root.val))
BinarySearchTree.p(root.left, depth + 2)
BinarySearchTree.p(root.right, depth + 2)
#staticmethod
def insert(node, val):
if not node:
return TreeNode(val)
elif node.val > val:
node.left = BinarySearchTree.insert(node.left, val)
else:
node.right = BinarySearchTree.insert(node.right, val)
return node
if __name__ == "__main__":
root = TreeNode(5)
for n in [2, 1, 3, 7, 9, 6]:
BinarySearchTree.insert(root, n)
BinarySearchTree.p(root)
Output:
5
2
1
3
7
6
9
Which amounts to:

Reconstructing a tree using inorder and preorder traversals in Python

I need to make a function that builds a tree from a preorder and inorder traversal, but I'm not sure where I should put the MakeNode and recursive calls to construct the tree properly.
Assuming inorder and preorder are both a list of ints, is the following algorithm correct to reconstruct the tree using the traversals?
def build(preorder, inorder):
root = preorder[0]
left subtree = inorder[:root-1]
right subtree = inorder[root+1:]
If so - How can one take that and construct a heap (ArrayHeap) using that algorithm recursively?
I have a class designed to construct nodes and then I can simply use heap.add(node) to create the heap.
Say my class to build a node is named "MakeNode" and is constructed as follows (for syntax purposes):
Class MakeNode():
def __init__(self, character, left=None, right=None):
To create the root node I would need to edit the function like this:
def build(preorder, inorder, heap):
root = preorder[0]
node = MakeNode(root) # Creating root node here
heap.add(node) # Adding to heap
left subtree = inorder[:root-1]
right subtree = inorder[root+1:]
But how should I use recursion to build the rest of the tree?
I can incorporate the left and right preorder for ordering purposes by doing this:
def build(preorder, inorder, heap):
root = preorder[0]
node = MakeNode(root)
heap.add(node)
left subtree = inorder[:root-1]
# order of left subtree = preorder[1:1+left subtree]
right subtree = inorder[root+1:]
# order of right subtree = preorder[root+1:]
I don't really know how to incorporate the recursive calls to build the tree or what exactly to put for the left or right parameters when doing so.
If anybody has any suggestions I would appreciate them, and I'm sorry if I've been unclear.
What you need to do is add the root of the pre-ordered list to the tree, and removing it from preorder list. Split the in order list as you are doing, then passing both the left and right branches recursively. Keep adding the first element of pre-order to the left of the previous node unless left_subtree is empty, then you need to add it to the right.
This is python code (already tested):
class Tree():
def __init__(self, inorder, preorder):
self.root = preorder[0]
lt = inorder[:inorder.index(self.root)]
rt = inorder[inorder.index(self.root) + 1:]
self.build(self.root, lt, rt, preorder[1:])
def build(self, last_node, left_subtree, right_subtree, preorder):
left_preorder = [node for node in preorder if node in left_subtree]
right_preorder = [node for node in preorder if node in right_subtree]
if len(left_subtree) > 0:
last_node.left = left_preorder[0]
lt = left_subtree[:left_subtree.index(last_node.left)]
rt = left_subtree[left_subtree.index(last_node.left) + 1:]
self.build(last_node.left, lt, rt, left_preorder)
if len(right_subtree) > 0:
last_node.right = right_preorder[0]
lt = right_subtree[:right_subtree.index(last_node.right)]
rt = right_subtree[right_subtree.index(last_node.right) + 1:]
self.build(last_node.right, lt, rt, right_preorder)
From http://www.cse.hut.fi/en/research/SVG/TRAKLA2/tutorials/heap_tutorial/taulukkona.html, you have:
parent(i) = i/2
left(i) = 2i
right(i) = 2i+1
so you can define a class:
class ArrayHeapNode:
def __init__(self, elements, index):
self.elements = elements
self.index = index
def left(self):
next = self.index * 2
if next >= len(self.elements):
return None
return ArrayHeapNode(self.elements, next)
def right(self):
next = (self.index * 2) + 1
if next >= len(self.elements):
return None
return ArrayHeapNode(self.elements, next)
def value(self):
return self.elements[self.index]
def set_value(self, _value):
self.elements[self.index] = _value
This gives you a class that can then function as a tree on an array representation of a binary heap according to the article. If there is no element in that branch, None is returned.
You can now create tree traversal algorithms (https://en.wikipedia.org/wiki/Tree_traversal):
def inorder_traversal(node, action):
if not node: return
inorder_traversal(node.left(), action)
action(node.value())
inorder_traversal(node.right(), action)
def preorder_traversal(node, action):
if not node: return
action(node.value())
preorder_traversal(node.left(), action)
preorder_traversal(node.right(), action)
These will also work with a traditional binary tree node:
class BinaryTreeNode:
def __init__(self, value, left, right):
self._value = value
self._left = left
self._right = right
def left(self):
return self._left
def right(self):
return self._right
def value(self):
return self._value
def set_value(self, _value):
self._value = _value
Now, you can make the traversal algorithms more flexible and python-like by doing:
def inorder(node):
if node:
for item in inorder(node.left()):
yield item
yield node.value()
for item in inorder(node.right()):
yield item
This allows you to write things like:
for item in inorder(tree):
print item
You can then count the elements from the node by doing:
n = sum(1 for e in inorder(root))
This then allows you to create an empty array capable of holding n elements for the elements in the heap:
elements = [0 for x in range(n)]
or combined:
elements = [0 for x in inorder(root)]
heap = ArrayHeapNode(elements, 0)
Now, you can iterate over both trees at the same time using:
for a, b in zip(inorder(root), inorder(heap)):
b = a
This should then assign all elements in the binary tree (root) to the correct elements in the array heap (heap) using inorder traversal. The same can be done by implementing a preorder function.
NOTE: I have not tested this code.
def pre_order(node):
print node #pre order ... print ourself first
pre_order(node.left)
pre_order(node.right)
def post_order(node):
post_order(node.left)
post_order(node.right)
print node # post order print self last...
def in_order(node):
in_order(node.left)
print node #in order ... between its children
in_order(node.right)
if you have any one of these you should be able to reproduce the tree
assume we have a tree like this
0
1 2
3 4 5 6
our traversals would be
0,1,3,4,2,5,6 #pre order
3,1,4,0,5,2,6 #in order
so from this we know that
zero is our root
3 is our left most deepest node
6 is our right most deepest node
0
...
3 6
our left over nodes are
1,4,2,5 # preorder
1,4,5,2 # in-order
from this we know that
1 is a child of zero
1 is the next level leftmost node
2 is the next level rightmost node
so we now have
0
1 2
3 6
leaving us with
4,5 # pre order
4,5 # in order
from this we know that 4 is a child of 1, and therefore 5 must be a child of 2 ...
now write a function that does all that
this article may help
http://leetcode.com/2011/04/construct-binary-tree-from-inorder-and-preorder-postorder-traversal.html

How would I fix this? builtins.AttributeError: 'NoneType' object has no attribute '_helper'

I keep on getting this error, and I don't know how I'd go about correcting it.
I'm trying to implement method count_less in class BST. And I'm writing a helper method in class _BSTNode and calling the helper within count_less using indirect recursion.
Thank you.
class BST:
"""A Binary Search Tree."""
def __init__(self: 'BST', container: list =[]) -> None:
"""
Initialize this BST by inserting the items from container (default [])
one by one, in the order given.
"""
# Initialize empty tree.
self.root = None
# Insert every item from container.
for item in container:
self.insert(item)
def __str__(self: 'BST') -> str:
"""
Return a "sideways" representation of the values in this BST, with
right subtrees above nodes above left subtrees and each value preceded
by a number of TAB characters equal to its depth.
"""
return self.root._str("") if self.root else ""
def insert(self: 'BST', item: object) -> None:
"""
Insert item into this BST.
"""
if self.root:
self.root.insert(item)
else:
self.root = _BSTNode(item)
def count_less(self: 'BST', item: object) -> int:
"""
Return the number of items in this BST that are strictly less tham
item.
"""
return self.root._helper(self.root, item)
class _BSTNode:
"""A node in a BST."""
def __init__(self: '_BSTNode', item: object,
left: '_BSTNode' =None, right: '_BSTNode' =None) -> None:
"""
Initialize this node to store item and have children left and right.
"""
self.item, self.left, self.right = item, left, right
def _str(self: '_BSTNode', indent: str) -> str:
"""
Return a "sideways" representation of the values in the BST rooted at
this node, with right subtrees above nodes above left subtrees and each
value preceded by a number of TAB characters equal to its depth, plus
indent.
"""
return ((self.right._str(indent + '\t') if self.right else '') +
indent + str(self.item) + '\n' +
(self.left._str(indent + '\t') if self.left else ''))
def insert(self: '_BSTNode', item: object) -> None:
"""
Insert item into the BST rooted at this node.
"""
if item < self.item:
if self.left:
self.left.insert(item)
else:
self.left = _BSTNode(item)
elif item > self.item:
if self.right:
self.right.insert(item)
else:
self.right = _BSTNode(item)
# else: # item == self.item
# pass # nothing to do: item is already in the tree
def _helper(self, item):
count = 0
if not self.item:
return 0
if self.item < item:
count += 1
count += count_less(self.left, item)
count += count_less(self.right, item)
return count
You didn't include a traceback, but the only reference to _helper in the code you've shown is here:
return self.root._helper(self.root, item)
The error message is telling you that self.root is None. Since you didn't show the code you ran to trigger this error, nobody can guess why you're calling it with self.root still None. But since BST.__init__() binds self.root to None, it's sure not surprising ;-)

Categories

Resources