π‘ Problem Formulation: A Symmetric Tree, also known as a Mirror Tree, is a binary tree in which the left subtree is a mirror reflection of the right subtree. In this article, we will explore methods to determine if a given binary tree is symmetric. For instance, a binary tree with elements [1, 2, 2, 3, 4, 4, 3] should be identified as symmetric.
Method 1: Recursive Approach
The recursive approach is a straightforward method that compares the left and right subtrees in a recursive fashion. Two nodes are symmetric if their values are equal, and the right subtree of each node is a mirror reflection of the left subtree of the other node.
β₯οΈ Info: Are you AI curious but you still have to create real impactful projects? Join our official AI builder club on Skool (only $5): SHIP! - One Project Per Month
Here’s an example:
class TreeNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None
def isMirror(t1, t2):
if not t1 and not t2:
return True
if not t1 or not t2:
return False
return (t1.val == t2.val) and isMirror(t1.right, t2.left) and isMirror(t1.left, t2.right)
def isSymmetric(root):
return isMirror(root, root)
# Example Tree
root = TreeNode(1)
root.left = TreeNode(2)
root.right = TreeNode(2)
root.left.left = TreeNode(3)
root.left.right = TreeNode(4)
root.right.left = TreeNode(4)
root.right.right = TreeNode(3)
print(isSymmetric(root))Output: True
This code snippet defines a TreeNode class to represent each node in the tree. It then utilizes helper function isMirror to recursively compare corresponding nodes in the two subtrees.
Method 2: Iterative Approach
The iterative approach emulates the recursive process using a queue. Each pair of nodes to be compared is placed in the queue, and the comparison is performed in a loop until the queue is empty.
Here’s an example:
from collections import deque
def isSymmetric(root):
if not root:
return True
queue = deque([(root.left, root.right)])
while queue:
t1, t2 = queue.popleft()
if not t1 and not t2:
continue
if not t1 or not t2:
return False
if t1.val != t2.val:
return False
queue.append((t1.left, t2.right))
queue.append((t1.right, t2.left))
return True
# Example usage with the same tree structure as above
print(isSymmetric(root))Output: True
This code example uses a queue to iteratively check pairs of nodes for symmetry, stopping and returning False if any asymmetry is detected, otherwise returning True once all pairs have been checked.
Method 3: Level-Order Traversal
This method involves performing a level-order traversal of the tree using a queue and checking if each level of the tree is a palindrome, indicating it is symmetric.
Here’s an example:
from collections import deque
def isSymmetric(root):
if not root:
return True
queue = deque([root])
while queue:
level = []
level_length = len(queue)
for _ in range(level_length):
node = queue.popleft()
if node:
level.append(node.val)
queue.append(node.left)
queue.append(node.right)
else:
level.append(None)
if level != level[::-1]:
return False
return TrueOutput: True
This code conducts a level-order traversal and uses list slicing to determine if the current level list is equal to its reverse, which would mean the level is symmetrical.
Method 4: Depth-First Search (DFS)
Using Depth-First Search (DFS), this method visits each branch and follows it to the end before backtracking, thereby checking symmetric properties for each sub-tree in a depth-first manner.
Here’s an example:
def isSymmetric(root):
def dfs(node1, node2):
if not node1 and not node2:
return True
if not node1 or not node2:
return False
if node1.val != node2.val:
return False
return dfs(node1.left, node2.right) and dfs(node1.right, node2.left)
return dfs(root, root)
# Same example tree and usage.
print(isSymmetric(root))Output: True
This code uses a DFS approach to explore each branch of the tree to the fullest extent before backtracking, ensuring the left and right sub-trees mirror each other.
Bonus One-Liner Method 5: Using Built-in Functions
For those seeking a highly concise solution, Python’s built-in functions can be leveraged to write a one-liner that checks if a tree is symmetric. This leverages methods 1-4, encapsulating the logic in a lambda expression.
Here’s an example:
isSymmetric = lambda root: (lambda f, r: f(r, r))(lambda t1, t2: t1 is t2 or (t1 and t2 and t1.val == t2.val and f(t1.left, t2.right) and f(t1.right, t2.left)), root) # Same example tree and usage. print(isSymmetric(root))
Output: True
This single-line function uses a lambda expression to create an isomorphic behavior to a recursive function, efficiently checking the mirror symmetry of a tree.
Summary/Discussion
- Method 1: Recursive Approach. Intuitive and elegant. Might suffer from stack overflow for very deep trees.
- Method 2: Iterative Approach. Uses a queue to avoid the pitfalls of deep recursion. May be slightly less intuitive but is more space efficient for broad trees.
- Method 3: Level-Order Traversal. Directly verifies symmetry at each level, thus is easy to understand. However, can be less efficient as it builds an extra list for each level.
- Method 4: Depth-First Search (DFS). Space efficient and logically clear, but also prone to stack overflow with deep trees.
- Bonus Method 5: Using Built-in Functions. Extremely succinct, but can be difficult to read and understand for those not well-versed in Python or functional programming concepts.
