new to python, I am doing leetcode problem 94, Binary Tree Inorder Traversal. Given the root of a binary tree, return the inorder traversal of its nodes' values.
I have found this code from https://leetcode-cn.com/problems/binary-tree-inorder-traversal/solution/dong-hua-yan-shi-94-er-cha-shu-de-zhong-xu-bian-li/
class Solution(object):
def inorderTraversal(self, root):
"""
:type root: TreeNode
:rtype: List[int]
"""
res = []
pre = None
while root:
if root.left:
pre = root.left
while pre.right:
pre = pre.right
pre.right = root
tmp = root
root = root.left
tmp.left = None
else:
res.append(root.val)
root = root.right
return res
However, I can't understand what tmp variable is doing here. It seems that the tmp variable is not used in any other places.
I tried to remove these 2 lines
tmp = root
tmp.left = None
But then I get a timeout error. Could anyone please explain what these 2 lines are doing here?
Go through the code step by step. The code wants to assign "move" root to the left, and then set the old root.left to None.
The two naive options fail:
root.left = None
root = root.left # root.left no longer is what it used to be because of the first line
or:
root = root.left
root.left = None # root no longer is what it used to be because of the first line
You can do without the tmp variable, however:
root.left, root = None, root.left
This works because Python evaluates the entire right hand side first, and then assigns the lhs from left to right.
tmp is necessary to remove the left child of root, otherwise it would keep looping.
Related
How to insert a node in a complete binary tree without using queue DS? I tried the following code:
class TreeNode:
def __init__(self, value=None) -> None:
self.left = None
self.value = value
self.right = None
class Tree:
def __init__(self, root=None) -> None:
self.__root = root if not root else TreeNode(root)
self.__len = 1 if root else 0
def append(self, data, root="_"):
if self.__root.value is None:
self.__root = TreeNode(data)
self.__len += 1
return
root = self.__root if root == "_" else root
if not root:
return False
if root.left is None and root.right is None:
root.left = TreeNode(data)
self.__len += 1
return True
elif root.left is not None and root.right is None:
root.right = TreeNode(data)
self.__len += 1
return True
elif root.left is not None and root.right is not None:
if self.append(data, root.left):
return
else:
self.append(data, root.right)
return
the recursive call of that function always add the new node on the left side of the tree, so what should I do to make it recursively checks the right side too?
First of all, the first line in your append code seems to give a special meaning to the value in the root node. When it is None it is not considered a real node, but to represent an empty tree. This is not a good approach. An empty tree is represented by a __root that is None -- nothing else. I would also suggest to remove the optional data argument from the constructor. Either the constructor should allow an arbitrary number of values or none at all. To allow one is odd and strengthens the idea that a tree could have a special None in its root node.
To the core of your question. There is nice attribute to complete binary trees. The paths from the root to a leaf can be represented by a bit pattern, where a 0 means "go left" and a 1 means "go right". And the path to the "slot" where a new node should be injected has a relationship with the size of the tree once that node has been added:
new size
binary representation
path to new node
1
1
[]
2
10
[left]
3
11
[right]
4
100
[left,left]
5
101
[left,right]
In general the path to the new node is defined by the bits in the binary representation of the new tree size, ignoring the leftmost 1.
This leads to the following code:
class Tree:
def __init__(self) -> None:
self.__root = None
self.__len = 0
def append(self, data):
self.__len += 1
if self.__len == 1: # First node
self.__root = TreeNode(data)
return
node = self.__root
# Iterate all the bits except the leftmost 1 and the final bit
for bit in bin(self.__len)[3:-1]:
node = [node.left, node.right][int(bit)] # Choose side
if self.__len & 1: # Use final bit to determine where child goes:
node.right = TreeNode(data)
else:
node.left = TreeNode(data)
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
I am practicing deleting node in BST and came across the following code.
def deleteNode(root, key):
if root is None:
return root
if key < root.key:
root.left = deleteNode(root.left, key)
elif(key > root.key):
root.right = deleteNode(root.right, key)
else:
if root.left is None:
temp = root.right
root = None
return temp
elif root.right is None:
temp = root.left
root = None
return temp
temp = minValueNode(root.right)
root.key = temp.key
root.right = deleteNode(root.right, temp.key)
return root
My question is do we need the line of root = None? According to reference counting, I feel root will be automatically destroyed as the only reference like parent.child is detached. Any explanation is greatly appreciated.
Given that root = None is immediately followed by return temp, it is just (re-)binding a local variable that is immediately discarded again and has no effect whatsoever.
In the given code, the lines root = None can be removed without changing the result of running the code.
Presumably the code was translated too literally from a different language where assigning to a variable changes the contents of a memory location.
But in Python, the assignment operator = just binds a new name1 to an already existing object (in this case it gives the name root to the object None) and does not change the object or any other object in memory.
1 at least with "simple names" on the left-hand side, it is a bit more complicated when assigning to something like a[i].
No, those lines aren't necessary. If you removed the early return in either branch, however, then you would need to set root = None.
Given the root node of a binary search tree (BST) and a value. You need to find the node in the BST that the node's value equals the given value. Return the subtree rooted with that node. If such node doesn't exist, you should return NULL.
this is what i get for my code:
class Solution:
def searchBST(self, root: TreeNode, val: int) -> TreeNode:
if root == None:
return None
elif root.val == val:
return root
elif root.val>val:
root = self.searchBST(root.left,val)
else:
root = self.searchBST(root.right,val)
which seems to output None.
but if replace the line
root = self.searchBST(root.left,val)
with
return self.searchBST(root.left,val)
same with root.right
then it works.
I am not too good at recursion but how can we do
return self.searchBST(root.left,val)
doesnt searchBST(..) return a TreeNode so dont we have to put the treenode in the variable root?
No as mentioned in question you need to return the node that matches the val.
In order to do that you have to return the address of the node if you find the value and None if does not.
Inorder to back propagate the value either the root address or Null(in case of not found) so you must return some address at every step.
If you are having problem with recursion go with the iterative traversal.
root iterativeSearch(struct Node* root, int key)
{
// Traverse untill root reaches to dead end
while (root != NULL) {
// pass right subtree as new tree
if (key > root->data)
root = root->right;
// pass left subtree as new tree
else if (key < root->data)
root = root->left;
else
return root; // if the key is found return 1
}
return Null;
}
Go to this for recursion visualisations:https://www.cs.usfca.edu/~galles/visualization/BST.html
You have to explicitly tell Python what you want the function to return. That's what you are doing with the return None and the return root lines.
The the left and right cases, you are only changing the local value of the parameter root, not changing anything outside of the scope of the function.
No explicit return is the same as return None.
Replacing the two root = by return should indeed do the work.
class Solution(object):
def is_leaf(self,root):
return root.left is None and root.right is None
def searchBST(self, root, val):
if root is None:
return root
if self.is_leaf(root):
if root.val == val:
return root
return None
if root.val == val:
return root
elif val < root.val:
return self.searchBST(root.left,val)
else:
return self.searchBST(root.right,val)
rI am trying to print out my binary tree in pre order form however I am coming across these errors. I am still learning python so I am not quite sure what is going on. But I assume that my print function isn't working properly. Not quite sure why preorder_print is having a global name issue though =/
my expected output would be
pre order:
4
2
1
3
8
6
10
Output:
pre order:
<BST_tree.Node instance at 0x0000000002AA0988>
<BST_tree.Node instance at 0x0000000002AA0E08>
<BST_tree.Node instance at 0x0000000002AA0E88>
my code:
class Node:
def __init__(self,value):
self.right = None
self.left = None
self.value = value
def BST_Insert(root, node): # root --> root of tree or subtree!
if root.value is None:
root = node # beginning of tree
else:
if root.value > node.value: # go to left
if root.left is None:
root.left = node
else:
BST_Insert(root.left, node)
else:
if root.value < node.value: # go to right
root.right = node
else:
BST_Insert(root.right, node)
def preorder_print(root):
print root
if root.left is not None:
preorder_print(root.left)
else:
if root.right is not None:
preorder_print(root.right)
r = Node(4)
# left
a = Node(2)
b = Node(1)
c = Node(3)
# right
d = Node(8)
e = Node(6)
f = Node(10)
BST_Insert(r, a)
BST_Insert(r, b)
BST_Insert(r, c)
BST_Insert(r, d)
BST_Insert(r, e)
BST_Insert(r, f)
print "pre order:"
preorder_print(r)
* EDIT *
Thank you everyone and especially abarnert for your help!!! Here is the fixed version! or the preorder_print and BST_Inert
def BST_Insert(root, node): # root --> root of tree or subtree!
if root.value is None:
root = node # beginning of tree
else:
if root.value > node.value: # go to left
if root.left is None:
root.left = node
else:
BST_Insert(root.left, node)
if root.value < node.value: # go to right
if root.right is None:
root.right = node
else:
BST_Insert(root.right, node)
def preorder_print(root):
print root.value
if root.left is not None:
preorder_print(root.left)
if root.right is not None:
preorder_print(root.right)
Apologies for posting two answers, but I'm not sure which of two problems you're asking about here.
Your preorder traversal isn't covering the entire tree, because you ignore the entire right subtree whenever the left subtree isn't empty:
def preorder_print(root):
print root
if root.left is not None:
preoder_print(root.left)
else:
if root.right is not None:
preorder_print(root.right)
So, in your example, because the 4 node has the 2 node on its left, it won't look at 8 or anything underneath it. And then the same thing in the 2. So, you only get 3 nodes instead of all 7.
To fix this, just remove the else:
def preorder_print(root):
print root
if root.left is not None:
preoder_print(root.left)
if root.right is not None:
preorder_print(root.right)
You also have a problem in your BST_Insert function. You're setting root.right = node any time node.value > root.value, even if there's already something there. So, the first time you try to insert something that's on the left side of the right side of anything, it will erase the parent—the 6 erases the 8, then the 10 erases the 6, so you end up with just 4, 2, 1, 3, and 10.
I think what you wanted here is to change this:
else:
if root.value < node.value: # go to right
root.right = node
else:
BST_Insert(root.right, node)
… to:
elif root.value < node.value: # go to right
if root.right is None
root.right = node
else:
BST_Insert(root.right, node)
The print function is working just fine. When you print out an object that doesn't have a custom __repr__ or __str__ method, this is exactly what you're supposed to get.
There are two ways to solve this.
First, instead of printing the Node object itself, print the information you want to print. For example, change this:
print root
… to:
print 'node with value {}'.format(root.value)
… or:
print root.value
… or:
print 'I've got a node and he's got a value and it's ' + str(root.value)
Alternatively, if you always want nodes to print out the same way—e.g., Node(4)—you can give the class a __repr__ method:
def __repr__(self):
return 'Node({})'.format(self.value)
Sometimes you want to provide both a nice human-readable representation of a class that you might put into a report, and a different representation that's useful for, e.g., experimenting at the interactive interpreter. In that case, you define both __str__ and __repr__:
def __str__(self):
# Pick whatever you think looks nice here
return str(self.value)
# return 'Node: ' + str(self.value)
# return 'Node with value {}'.format(self.value)
def __repr__(self):
return 'Node({})'.format(self.value)
(Notice that Node(4) is a nice "experimenting at the interactive interpreter" representation, because it's exactly what you'd type into the interpreter to create an equivalent object.)
Use print root.value instead of print root.
Explanation:
root is an object, an instance of the Node class. root.value is the actual number the node holds.
Aside: the "proper" way to do this would be what #abarnert answered, via __repr__, but it's a little overkill for simple exercises focused around teaching about trees.
You want to print the value of root
print root.value