Techniques used in checking if a binary tree is symmetric - python

Given a binary tree, check whether it is a mirror of itself (ie, symmetric around its center).
Question link is here
The recursion method need to traverse the tree twice.
But one of the comment provided a solution used a technique called 'Null check'. I can't understand why in this way can we avoid checking the tree twice?
Here is his code in C++:
bool isSymmetric(TreeNode* root) {
if (!root) return true;
return isSymmetric(root->left, root->right);
}
bool isSymmetric(TreeNode* t1, TreeNode* t2){
if (!t1 && !t2) return true;
if (!t1 || !t2) return false;
return t1->val == t2->val
&& isSymmetric(t1->left, t2->right)
&& isSymmetric(t1->right, t2->left);
}
I have also tried to modify it into python3 and my code also passed all test cases!
Here is my code:
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def isSymmetric(self, root):
return self.helper(root)
def helper(self,root):
if root is None:
return True
#why we can redefine the helper here?
def helper(left,right):
if left is None and right is None:
return True
if left is None or right is None:
return False
return left.val==right.val and helper(left.left,right.right) and helper(left.right,right.left)
return helper(root.left,root.right)
I have never met such kind of recursion before.
(1) Why we can redefine the function helper with different arguments in helper function itself?
(2) My intuition tells me that helper function will stop execution once it returns back to the root thus the tree won't be checked twice. But I don't know why.

A def statement is really just a fancy assignment statement. In Solution.helper, you are defining a local variable named helper that is bound to another function. As a result, all references inside Solution.helper and the local function to the name helper resolve to the local function.
Solution.helper is not a recursive function; only the local function is. You could write the same thing (less confusingly but equivalently) as
class Solution:
def isSymmetric(self, root):
return self.helper(root)
def helper(self,root):
if root is None:
return True
def helper2(left,right):
if left is None and right is None:
return True
if left is None or right is None:
return False
return left.val==right.val and helper2(left.left,right.right) and helper2(left.right,right.left)
return helper2(root.left,root.right)

The role of function isSymmetric(TreeNode* root is pretty simple. First, it returns true if the tree is empty, and if it's not, it checks if its left child is a mirror of its right child, which happens in the isSymmetric(TreeNode* t1, TreeNode* t2). So let's try to understand how the second function works. It is essentially designed to take two trees and check if they are mirrors of each other. How? First, it does the obvious checks. If one is null and the other is not, it returns false, and if both are null it returns true. The interesting part happens when both are potentially trees. It suffices that the left child of one is the mirror of the right child of the other and vice versa. You can draw a tree to see why this is the case. A schema should be self-explanatory.

Related

Deleting node in BST (python)

Trying to build a binary search tree in python and came across this weird bug. After deleting nodes using my delete_node function, deleted nodes are still being printed, but only ones that are being deleted properly are nodes that have two other nodes attached to it (these ones are supposed to be hardest to delete though)
Here's the code:
class Node:
def __init__(self, data):
self.Left = self.Right = None
self.T_data = data
# function that deletes nodes from the tree
def delete_node(self, item):
if self is None:
return self
elif item < self.T_data:
self.Left.delete_node(item)
elif item > self.T_data:
self.Right.delete_node(item)
else:
# case when the node we want to delete has no leaves attached to it
if self.Right is None and self.Left is None:
self = None
# cases when a node has either left or right leaf node
elif self.Left is None:
temp = self.Right
self = None
return temp
elif self.Right is None:
temp = self.Left
self = None
return temp
else: #case when a node has two leaf nodes attached
temp = self.Right.min_node()
self.T_data = temp.T_data
self.Right = self.Right.delete_node(temp.T_data)
return self
As you can see the way nodes are deleted is using a recursion, so for double-branched nodes to get deleted, the single-branch node deletion should work properly, but it does not.
heres the print function and how the functions are called:
# function that prints contents of the tree in preorder fashion
def print_tree_preorder(self):
if self is None:
return
print("%s" % self.T_data)
if self.Left is not None:
self.Left.print_tree_preorder()
if self.Right is not None:
self.Right.print_tree_preorder()
x = int(input("Which element would you like to delete?\n"))
root = root.delete_node(x)
root.print_tree_preorder()
What you're doing right now, when you have:
self = None
Is not actually deleting the object itself. What you're doing is assigning self to a different value.
I think a good way to illustrate this problem is thinking of self and other variables as a tag.
When you say:
a = 3
You are essentially having the tag a put on the entity 3. 3 resides somewhere in memory, and a "points" to 3(although pointers in C++ isn't really the references in python, so be careful if you're going to make that comparison).
When you point self to None, what you wanted to say was:
So I want to remove this object, and all things that point to this object will point to None instead.
However, what you're currently saying is:
So I want to set my self tag to point to None.
Which is completely different. Just because you set your self tag to None does not mean you set the node's parents .Right or .Left members to None as well.
The solution? Well, you're not gonna like this, but you're gonna have to either:
have a pointer to the parent for each node, and set the parent's child(this child specifically) to None.
check 1 levels deeper in your tree, so you can delete the child node instead of deleting the node itself.
The reason the case for 2 node children works is because you're setting the attribute of the object here, instead of setting self=None. What this means is that you're still pointing to the same object here, specifically on this line:
self.T_data = temp.T_data
It's the difference between "Coloring a object does not make it a different object. Its traits are just different" vs. "replacing a object with another object makes it a different object".

Why does recursive function for travelling to front of doubly linked list not work?

I am a novice who has just finished edX's introductory course MIT 6.00.1x; the following is related to a problem on that course's final exam (now concluded, so I can seek help). Let
def class DLLNode(object):
def __init__(self, name):
self.cargo = cargo
self.before = None
self.after = None
def setBefore(self, before): self.before = before
def setAfter(self, after): self.after = after
def getBefore(self): return self.before
def getAfter(self): return self.after
def getCargo(self): return self.cargo
be used to create a doubly linked list. Suppose node is an instance of class DLLNode that appears in a doubly linked list. Then node.getBefore() returns that node's immediate predecessor in the list, except that it returns None if node is at the front of the list and so has no predecessor.
I have written a recursive function
def firstInList(nodeInList):
""" Prints out the cargo carried by the first node in that doubly linked list
of which nodeInList is a part. Returns that first node. """
if nodeInList.getBefore() == None:
firstnode = nodeInList
print firstnode.getCargo()
return firstnode
# nodeInList.getBefore() is not None, so nodeInList has an immediate predecessor
# on which firstInList can be be called.
firstInList(nodeInList.getBefore())
that I wish to return the first node in a doubly linked list, given as argument a known node nodeInList in the list.
My problem: firstInList arrives at the correct first node, as evidenced by its printing the first node's cargo regardless of the specific nodeInList used. But whenever nodeInList is not the first node in the linked list, the return value of firstInList(node) turns out to be None rather than the desired first node. This conclusion is based on the following: If, for example, the list's first node node1 has cargo 1 and is followed by node2 with cargo 2, then firstInList(node2) == None evaluates as True but firstInList(node2) == node1 evaluates as False. A call firstInList(node2).getCargo() will return an error message
Attribute Error: 'NoneType' object has no attribute 'getCargo'
Another datum is that firstInList(node1) == node1 evaluates as True; that, at least, is as I would expect.
This suggests the firstnode found is not being returned back up the chain of recursive calls in the way I have imagined. Can anyone explain why?
(Please do not suggest that I use iteration instead of recursion. I know how to do that. I am trying to understand Python 2.7's behavior for the code as written.)
Well, it would appear that you're not returning the result of the recursion, so the function will in all cases but the degenerate simply return the default uninitialized value.
The last line should be:
return firstInList(nodeInList.getBefore())
Many thanks to Nathan Tuggy. At first I misunderstood what you were saying, but in fact you were correct.
My firstInList function worked perfectly once I changed the last line
firstInList(nodeInList.getBefore())
to read
return firstInList(nodeInList.getBefore()) .
Given the ridiculous number of hours I've spent worrying about this, I think this is a type of mistake I'm not likely to make in the future. Or if I do, I'll be able to discover the problem myself.

leaves_and_internals Function

This question is for school (homework) so I am not asking for code, and I don't want any, just an idea. I have to write a function that returns two lists, a list of the leaves and a list of the internal nodes of a binary tree. My algorithm is:
1) If both the left and the right subtrees are None, it is a leaf, and so I add it to the leaves list.
2) If they are not, then I add it to the internals list, and call the function on the left subtree, and then on the right, if they exist.
This is the code I have written:
def leaves_and_internals(self):
leaves = []
internals = []
if self.left is None and self.right is None:
leaves.append(self.item)
else:
internals.append(self.item)
if self.left != None:
leaves_and_internals(self.left)
else:
leaves_and_internals(self.right)
return internals, leaves
I'm pretty sure that the algorithm is correct, but I think that every time I recurse on the Nodes, the lists will get reset. How can I get around this?
Any help is greatly appreciated. Thanks
I have not looked into the algorithm of your code, and just merely suggesting an answer to the problem you're stuck at. You could pass leaves and internals as arguments to the recursive function, so that their contents get retained across the recursive calls.
In python, if you pass a mutable object to a function/method, the function/method gets a reference to the object. So as long as you still treat it as the same mutable object (i.e. not assign the parameter with something else directly), any changes you make to the object are also visible to the caller. Since list is a mutable type, this behavior is very much helpful for the case you're interested in.
And make sure to initialize the lists to [] before calling the leaves_and_internals function from outside.
def leaves_and_internals(self, leaves, internals):
if self.left is None and self.right is None:
leaves.append(self.item)
else:
internals.append(self.item)
if self.left != None:
leaves_and_internals(self.left, leaves, internals)
else:
leaves_and_internals(self.right, leaves, internals)
return
# Somewhere outside
leaves = []
internals = []
myobj.leaves_and_internals(leaves, internals)
UPDATE:
Since the OP mentions he cannot change the signature of the method nor use instance variables, this is an alternate solution I can think of which returns the leaves and internals to the caller. BTW, I assume some nodes in your tree can have both left and right, so you would need to check both (i.e. use 2 separate if instead of an if...else).
def leaves_and_internals(self):
leaves = []
internals = []
if self.left is None and self.right is None:
leaves = [ self.item ]
else:
if self.left != None:
leaves, internals = leaves_and_internals(self.left)
if self.right != None:
templeaves, tempinternals = leaves_and_internals(self.right)
leaves += templeaves
internals += tempinternals
internals.append(self.item)
return leaves, internals

Determine if two dictionaries are equal Python error

I am creating a doubly linked structure and am having some issues with comparing if two nodes are equal. The structure is fairly complex in that it has multiple attributes including name, row, column, right, left, up, and down. If two nodes are equal they must agree on all of these attributes. I know in my eq method I could simply hard code checking each attribute versus the other but I figured there would be an easier way to do it and found a way that works most of the time. Thus I have the following:
def __init__ (self,row,col,name=None,up=None,down=None,left=None,right=None):
self.name = name
self.row = row
self.col = col
self.up = up
self.down = down
self.left = left
self.right = right
def __eq__ (self, other):
return vars(self) == vars(other)
And various other methods that aren't really important to this. So my shortcut for determining whether two Nodes was to basically look at the dictionary of their variables and let python compare the two dictionaries for equivalence.
This works great! As long as the two nodes are actually equal. It returns True and I go on my merry way with my code. BUT if the two nodes are actually not equal it falls apart. I get
File "*filename*", line 35 in __eq__ return vars(self) == vars(self)
written to the screen numerous amounts of times until it finally says
RuntimeError: maximum recursion depth exceeded
I know there are some ways around this, i.e. I could explicitly check each attribute, but that's lame and I want to know why this isn't working, and if it can be easily fixed. I have tested this method with other simpler dictionaries and it works so my thought is that the issue has something to do with determining if objects are equal but I have no idea what I could do here. I realize I could also just do a error catch and then make that return False but something other than those two solutions would be appreciated,
It looks like your up, down, etc are pointing to other instances of your class.
Your comparison code is basically saying, to test if self == other, does self.up == other.up? does self.up.up == other.up.up? etc. And then recursing until it runs out of space.
You may instead want to use
def __eq__(self, other):
return self.name == other.name \
and self.row == other.row \
and self.col == other.col \
and self.up is other.up \
and self.down is other.down \
and self.left is other.left \
and self.right is other.right
I have no python at hand, but I guess this is what happens:
in the __dict__ of self and in the __dict__ of other is areference to one of your nodes
now this node is compared for equality (once the one from vars, once the one from other), this causes your comparison method to be called.
If you now have a loop (e.g common parent) you get infinite recursion:
in original comparison:
compare self.parent to other.parent
in parent comparison:
compare self.parent.child to other.parent.child
(parent and child refer to your up and down)
try(untested):
def __eq__(self, other):
for s, o in zip(vars(self),vars(other)):
if not s is o and s != o:
return False
return True
basically what Hugh Bothwell suggested, just in a loop. First check if you have the same object in memory, if so don't compare them, otherwise test.

Python classes -- mutability

Im having a problem with python.. I have a binary tree node type:
class NODE:
element = 0
leftchild = None
rightchild = None
And I had to implement a function deletemin:
def DELETEMIN( A ):
if A.leftchild == None:
retval = A.element
A = A.rightchild
return retval
else:
return DELETEMIN( A.leftchild )
Yet, when I try to test this on the binary tree:
1
/ \
0 2
It should delete 0, by just setting it to null but instead, i get this:
0
/ \
0 2
Why can I not nullify a node within a function in python? Is their a way to do this?
Python passes arguments by object-reference, just like java, not by variable-reference. When you assign to a local variable (including an argument) to a new value, you're changing only the local variable, nothing else (don't confuse that with calling mutators or assigning to ATTRIBUTES of objects: we're talking about assignments to barenames).
The preferred solution in Python is generally to return multiple values, as many as you need, and assign them appropriately in the caller. So deletemin would return two values, the current returnval and the modified node, and the caller would assign the latter as needed. I.e.:
def DELETEMIN( A ):
if A.leftchild is None:
return A.element, A.rightchild
else:
return DELETEMIN( A.leftchild )
and in the caller, where you previously had foo = DELETEMIN( bar ), you'd use instead
foo, bar = DELETEMIN( bar )
Peculiar capitalization and spacing within parentheses, BTW, but that's another issue;-).
There is no way to get "a pointer or reference to a caller's barename" (in either Python or Java) in the way you could, e.g., in C or C++. There are other alternative approaches, but they require different arrangements than you appear to prefer, so I recommend the multiple return values approach as here indicated.
class Node:
element = 0;
left_child = None
right_child = None
def delete_min( A ):
if A.left_child is None:
return A.right_child
else:
A.left_child = delete_min(A.left_child)
return A
tree = delete_min(tree)

Categories