Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 12 months ago.
Improve this question
This is the question
https://leetcode.com/problems/same-tree/
Question:
Given the roots of two binary trees p and q, write a function to check if they are the same or not.
Two binary trees are considered the same if they are structurally identical, and the nodes have the same value.
I have used Python for solving this problem
This is my approach. Could you tell why it failed the given test case?
https://leetcode.com/submissions/detail/661792014/
My approach:
#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 isSameTree(self, p: Optional[TreeNode], q: Optional[TreeNode]) -> bool:
a = m = p
b = n = q
if p is None and q is None:
return True
elif p is None or q is None:
return False
while a:
if a.val != b.val:
return False
if a.left:
a = a.left
if b.left:
b = b.left
else:
return False
else:
if b.left:
return False
else:
break
while m:
if m.val != n.val:
return False
if m.right:
m = m.right
if n.right:
n = n.right
else:
return False
else:
if n.right:
return False
else:
break
return True
The problem is that in your while loop, m will go all the way down via the same-side child (first loop: left, second loop right), but when it reaches the end, it will not backtrack and then look at all the opposite sided subtrees it had skipped along the way.
For example, take this tree:
4
/ \
2 6
/ \ / \
1 3 5 7
The first loop will check the left side (i.e. 4, 2 and 1), and the second loop will check the right side (i.e. 4, 6, 7), but there is no provision to go down the tree in a zig-zag way, so the nodes with 3 and 5 are never checked.
What you need here, is recursion. Solve the problem recursively for the left subtree and again recursively for the right subtree. If either returns that there is a difference, stop, and return False. If both calls give a positive result, and also the current node is equal, return True.
The solution (spoiler):
def isSameTree(self, p: Optional[TreeNode], q: Optional[TreeNode]) -> bool:
return bool(not p and not q or
p and q and p.val == q.val
and self.isSameTree(p.left, q.left)
and self.isSameTree(p.right, q.right))
Related
This question already has answers here:
Why does my recursive function return None?
(4 answers)
Closed 7 months ago.
I'm trying to create a tree with n children for each node.
Problem is, when I try to implement this using a recursive function, I ends up with multiple recursive calls so I can't have a single return statement, hence having None as a final result.
Here is my piece of code :
def recursive_func(tree, n):
if n == 0:
return tree
else:
permutations = get_permutations()
for permutation in permutations:
child_tree = recursive_func(Tree(permutation), n-1)
tree.addChild(child_tree)
get_permutations() gives a list of child trees to create. I also have a Tree class with a node value and a list of children.
Here is the Tree class:
class Tree:
def __init__(self, result):
self.node = node
self.children = []
def addChild(self, tree):
self.children.append(tree)
This is probably a rookie error in the design of my problem, but I would be glad to get some help.
TLDR: Since you use the result of recursive_func, it should always return its tree.
The recursive_func has three important points for this problem:
def recursive_func(tree, n):
if n == 0:
return tree # 1.
else:
permutations = get_permutations()
for permutation in permutations:
child_tree = recursive_func(Tree(permutation), n-1) # 2.
tree.addChild(child_tree)
# 3.
Now, 1. defines that the function sometimes returns a Tree. This matches 2. which always expects the function to return a Tree. However, both conflict with 3., which implicitly returns None when the second branch is done.
Since the first branch is empty aside from the return, both 1. and 3. can be collapsed to one path that always returns a Tree.
def recursive_func(tree, n):
if n > 0:
permutations = get_permutations()
for permutation in permutations:
child_tree = recursive_func(Tree(permutation), n-1)
tree.addChild(child_tree)
return tree
For practice, I solved Leetcode 101. Symmetric Tree question:
Given a binary tree, check whether it is a mirror of itself (ie, symmetric around its center).
I have an idea to do in order traversal, record each node value into list and check the value from the first part, and reverse the second part from the list. But
it failed on test case [1,2,3,3,null,2,null]
from my local, my value return [3, 2, None, 1, 2, 3, None], but from leetcode it return [3,2,1,2,3] anyone know why and anything wrong with my code?
def isSymmetric(root: 'TreeNode') -> 'bool':
if not root: return True
value = []
def traversal(cur):
if cur:
traversal(cur.left)
value.append(cur.val)
traversal(cur.right)
traversal(root)
size = int(len(value) / 2)
return value[:size] == value[size + 1:][-1::-1]
I'm afraid inorder traversal does not uniquely determine a tree. e.g. a tree with structure
1
\
2
\
3
has the same inorder traversal as
2
/ \
1 3
Since you have the if cur condition, your inorder traversal won't include null nodes, which makes the traversal non-unique. You can include the null nodes like this:
def traverse(cur):
if cur:
traverse(cur.left)
values.append(cur.val if cur else None)
if cur:
traverse(cur.right)
This would serialize the tree nodes uniquely.
What you can also do is in this case determine the structure of the left node and right node are the same (except left and right are reversed). Here is my accepted solution:
class Solution:
def isSymmetric(self, root: 'TreeNode') -> 'bool':
if not root:
return True
return self.isSymmetricHelper(root.left, root.right)
def isSymmetricHelper(self, node1, node2):
if node1 is None and node2 is None:
return True
if node1 is None or node2 is None:
return False
if node1.val != node2.val: # early stopping - two nodes have different value
return False
out = True
out = out and self.isSymmetricHelper(node1.left, node2.right)
if not out: # early stopping
return False
out = out and self.isSymmetricHelper(node1.right, node2.left)
return out
It recursively check if two trees are the mirror of each other (with some early stopping). The idea is if two trees are mirror, the left subtree of tree1 must be the mirror of the right subtree of tree2, same applies for right subtree of tree1 and left subtree of tree2.
Although the runtime of both are O(n), he recursive method takes O(logn) average space (used by call stack) and has early stopping built-in, while your serialize-all-nodes method takes O(n) space O(n) time.
this is how the symmetric tree is:
class Solution:
def isSymmetric(self, root: Optional[TreeNode]) -> bool:
def is_mirror(t1,t2):
# If I reached all the way down that means I always got True.
if t1 is None and t2 is None:
return True
# if one of them is None but other one is not then False
if t1 is None or t2 is None:
return False
# 2=2 and t1.left==t2.right and t1.right==t2.left
return t1.val==t2.val and is_mirror(t1.left,t2.right) and is_mirror(t1.right,t2.left)
return is_mirror(root.left,root.right)
I am trying to do a preorder traversal of binary tree using a linked list.
class BTNode:
"""A node in a binary tree."""
def __init__(self: 'BTNode', item: object,
left: 'BTNode' =None, right: 'BTNode' =None) -> None:
self.item, self.left, self.right = item, left, right
class LLNode:
"""A node in a linked list."""
def __init__(self: 'LLNode', item: object, link: 'LLNode' =None) -> None:
self.item, self.link = item, link
def __str__(self: 'LLNode') -> str:
"""Return an informative string showing self
>>> b = LLNode(1, LLNode(2, LLNode(3)))
>>> str(b)
'1 -> 2 -> 3'
"""
return str(self.item) + (' -> ' + str(self.link) if self.link else '')
def preorder(root: BTNode) -> LLNode:
"""Return the first node in a linked list that contains every value from the
binary tree rooted at root, listed according to an preorder traversal.
>>> b = BTNode(1, BTNode(2), BTNode(3))
>>> repr(preorder(b))
'LLNode(1, LLNode(2, LLNode(3)))'
>>> b2 = BTNode(4, BTNode(5))
>>> b3 = BTNode(7, b, b2)
>>> str(preorder(b3))
'7 -> 1 -> 2 -> 3 -> 4 -> 5'
"""
return _preorder(root)[0]
def _preorder(root: BTNode) -> (LLNode, LLNode):
"""Return the first and last nodes in a linked list that contains every
value from the binary tree rooted at root, listed according to an preorder
traversal.
"""
if not root:
return None, None
left_head, left_tail = _preorder(root.left)
right_head, right_tail = _preorder(root.right)
# change from right_tail = left_tail to right_tail = left_head
if not right_tail:
right_tail = left_head
if not left_head:
left_head = right_head
if left_tail:
left_tail.link = right_head
root_node = LLNode(root.item, left_head)
return root_node, right_tail
I am always getting '7 -> 1 -> 2' instead of '7 -> 1 -> 2 -> 3 -> 4 -> 5' as my output in preorder function. I am not quite sure why. Could someone please tell me how I can edit my current code to fix this problem?
You appear to have an error in your preorder code dealing with returns like LLNode(value, None).
Specifically, when you are traversing BTNode(a, BTNode(b), BTNode(c)) where neither b nor c has children, you don't merge correctly. You'll want to have another look at your logic for this case.
You haven't returned the tail of the list properly. I added some debugging instrumentation to trace the operation of _preorder -- which is something you should do before posting here. Debugging is a critical skill.
indent = ""
def _preorder(root: BTNode) -> (LLNode, LLNode):
"""Return the first and last nodes in a linked list that contains every
value from the binary tree rooted at root, listed according to an preorder
traversal.
"""
global indent
print(indent, " ENTER", root.item if root else "NULL")
if not root:
return None, None
indent += " "
left_head, left_tail = _preorder(root.left)
print (indent, root.item, "Left ", left_head, left_tail, str(left_head))
right_head, right_tail = _preorder(root.right)
print (indent, root.item, "Right", right_head, right_tail, str(right_head))
if not right_tail:
right_tail = left_tail
if not left_head:
left_head = right_head
if left_tail:
left_tail.link = right_head
root_node = LLNode(root.item, left_head)
print (indent, "LEAVE", root.item, right_tail.item if right_tail else "NULL")
indent = indent[2:]
return root_node, right_tail
Output for the full traversal is below. You can see that you never link in the right side properly; I'll leave the repair as an exercise for the student. :-)
ENTER 7
ENTER 1
ENTER 2
ENTER NULL
2 Left None None None
ENTER NULL
2 Right None None None
LEAVE 2 NULL
1 Left 2 None 2
ENTER 3
ENTER NULL
3 Left None None None
ENTER NULL
3 Right None None None
LEAVE 3 NULL
1 Right 3 None 3
LEAVE 1 NULL
7 Left 1 -> 2 None 1 -> 2
ENTER 4
ENTER 5
ENTER NULL
5 Left None None None
ENTER NULL
5 Right None None None
LEAVE 5 NULL
4 Left 5 None 5
ENTER NULL
4 Right None None None
LEAVE 4 NULL
7 Right 4 -> 5 None 4 -> 5
LEAVE 7 NULL
Main: 7 -> 1 -> 2
RESPONSE TO OP UPDATE
Obviously, that fixed part of your problem. Now, let's look at what happens when you return from the calls for node 1's left and right subtrees, and try to link those properly into the linear list:
left_head, left_tail = _preorder(root.left)
# returns 2, None
right_head, right_tail = _preorder(root.right)
# returns 3, None
if not right_tail:
right_tail = left_head
# right_tail is now node 2; this isn't correct: node 3 should be in that spot.
if not left_head:
# left_head is node 2; not an issue now
if left_tail:
# left_tail is None; not an issue now
return root_node, right_tail
# You return nodes 1 and 2;
# you never linked node 2 to node 3.
# You need to fix this.
I am currently having problem writing a function that should return a suggested move i.e. a simple computer opponent for a game of connect 4.
The following is some functions that I have written (and work correctly for the situations I have tested) but are used in the computeropponent function.
import random
#board: a list containing 6 lists with 7 elements each (a connect4 board)
#0 represents an empty space, and 1,2 represent player1 and player2
#turn: whose turn it is (i.e. player1 or player2)
#move: column they want to make a move in (i.e 0-6, but will be 1-7 to the player)
def validmoves(board):
"""This function iterates through the board to find all the valid moves
(i.e. it excludes the columns that are filled) and returns the list of
columns with valid moves"""
vm = []
for j in range(7):
i = 5
while vm.count(j) == 0 and i>=0:
if board[i][j] == 0:
vm.append(j)
i -= 1
return vm
def makemove(board,move,turn):
"""This function places turn's player piece in the move'th column and
returns the board"""
for i in reversed(board):
if i[move] == 0:
i[move] = turn
return board
def winner(board,turn):
"""This function checks if the player who just played a turn has won"""
#horizontals
for i in board:
for j in range(4):
if i[j]==turn and i[j+1]==turn and i[j+2]==turn and i[j+3]==turn:
return True
#verticals
for j in range(7):
for i in range(3):
if board[i][j]==turn and board[i+1][j]==turn and board[i+2][j]==turn and board[i+3][j]==turn:
return True
#positive diagonals
for j in range(4):
for i in range(3):
if board[i][j]==turn and board[i+1][j+1]==turn and board[i+2][j+2]==turn and board[i+3][j+3]==turn:
return True
#negative diagonals
for j in range(4):
for i in range(5,2,-1):
if board[i][j]==turn and board[i-1][j+1]==turn and board[i-2][j+2]==turn and board[i-3][j+3]==turn:
return True
return False
The following is the code I have a problem with
def computeropponent(board,turn):
#the following defines the other player in the context of this function
if turn == 1:
notturn = 2
elif turn == 2:
notturn = 1
"""for the following loops, it only computes the first loop and then skips straight to
the last line."""
for move in validmoves(board):
if winner(makemove(board,move,turn),turn)==True:
return move
for move in validmoves(board):
if winner(makemove(board,move,notturn),turn)==True:
return move
return random.choice(validmoves(board))
i.e. if i were to swap the order of the for loops (or set turn to 1 in
computer opponent), it will return the correct answer (which should be 0 in the test below), however in this case it just returns a random element from the list of valid moves.
board = [[0,0,0,0,0,0,0],
[0,0,0,0,0,0,0],
[0,0,0,0,0,0,0],
[0,0,0,0,1,2,0],
[0,0,0,1,2,2,0],
[0,1,1,1,2,1,0]]
print(validmoves(board))
print(computeropponent(board,2))
I apologise in advance for the messy code and length of my post. I have not been programming long and this is my first time posting on stackexchange, and thanks in advance for the help.
I don't understand, why i am so incapable of coming up with a simple recursive function to count the number of leaves on a binary tree. I am ashamed to say, I've just been blank and staring at the monitor trying to figure out why everything doesn't work.
Why is it so difficult to realize, what works and what doesn't? Is this supposed to be intuitive or unintuitive?
def num_leaves(tree):
if (tree.get_left() is None) and (tree.get_right is None()):
return 1
#something goes here..
return #something here..
Can someone offer some advice why I may not finding this as simple as its suppose to be
Thanks
I suspect that this is one of the first few times you've dealt with recursion. I say this, because I felt the same way, my first few times.
You have the correct idea to start with: you've identified and (correctly) implemented your base case. So, let's write down some thoughts about the solution before we actually code it up:
Basic Idea:
Identify all the leaves of a BTree
If a node has no children, it is a leaf
If a node does have children, it is not a leaf. Count the number of leaves on the left BTree and the number of nodes on the right BTree and add them up
Ok now that we have the basic idea, let's try some pseudocode:
function countLeaves(rootNode):
if nootNode has no children: # this is a leaf
return 1
if rootNode has a left child: # non-leaf nodes may be missing a left or right child
leftLeaves = countLeaves(left child of rootNode)
else:
leftLeaves = 0
if rootNode has a right child:
rightLeaves = countLeaves(right child of rootNode)
else:
rightLeaves = 0
return leftLeaves + rightLeaves
Make sense? Ok, let's write some python code:
def countLeaves(root):
if (root.get_left() is None) and (root.get_right() is None): # we are a leaf
return 1
leftChild = root.get_left()
if leftChild is not None:
leftChildren = countLeaves(leftChild)
else:
leftChildren = 0
rightChild = root.get_right()
if rightChild is not None:
rightChildren = countLeaves(rightChild)
else:
rightChildren = 0
return leftChildren + rightChildren
Now that we have that idea coded up, let's clean it up a bit:
def countLeaves(root):
if root.get_left() is None and root.get_right() is None: return 1
return (0 if root.get_left() is None else countLeaves(root.get_left())) + (0 if root.get_right() is None else countLeaves(root.get_right()))