flowchart LR
subgraph p ["Tree p"]
A(1):::orange
B(2):::orange
C(3):::orange
A --- B & C
end
subgraph q ["Tree q"]
D(1):::green
E(2):::green
F(3):::green
D --- E & F
end
p <==>|Identical| q
classDef green fill:#3CB371,stroke:#000,stroke-width:1px,color:#fff;
classDef blue fill:#0000FF,stroke:#000,stroke-width:1px,color:#fff;
classDef orange fill:#DC582A,stroke:#333,stroke-width:2px;
linkStyle 4 stroke:blue,stroke-width:2px
flowchart LR
subgraph p ["Tree p"]
A(1)
B(2)
A --- B
A ~~~ N1:::hidden
end
subgraph q ["Tree q"]
D(1)
E(2)
D ~~~ N2:::hidden
D --- E
end
p <==>|Not Identical| q
classDef hidden display:none
⏰ Time complexity: O(n) — Each node in both trees is visited exactly once.
🧺 Space complexity: O(h) — The maximum depth of the recursion stack is the height of the tree (h). In the worst case (skewed tree), this is O(n); for a balanced tree, it is O(log n).
classSolution:
defisSameTree(self, p: Optional[TreeNode], q: Optional[TreeNode]) -> bool:
# If both nodes are null, they are identical.ifnot p andnot q:
returnTrue# If one is null or their values are different, they are not identical.ifnot p ornot q or p.val != q.val:
returnFalse# Recursively check the left and right subtrees.return self.isSameTree(p.left, q.left) and self.isSameTree(p.right, q.right)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
use std::rc::Rc;
use std::cell::RefCell;
impl Solution {
pubfnis_same_tree(p: Option<Rc<RefCell<TreeNode>>>, q: Option<Rc<RefCell<TreeNode>>>) -> bool {
match (p, q) {
(None, None) =>true,
(Some(p), Some(q)) => {
let p = p.borrow();
let q = q.borrow();
p.val == q.val
&& Self::is_same_tree(p.left.clone(), q.left.clone())
&& Self::is_same_tree(p.right.clone(), q.right.clone())
}
_ =>false,
}
}
}
Instead of recursion, we can use queues to traverse both trees in parallel, level by level. By comparing nodes at each level, we can efficiently check for structural and value equality without relying on the call stack.
⏰ Time complexity: O(n) — Each node in both trees is enqueued and dequeued exactly once.
🧺 Space complexity: O(w) — The maximum number of nodes in the queue at any time is the width of the tree (w). In the worst case (complete binary tree), this is O(n); for a skewed tree, it is O(1).
Instead of using recursion or queues, we can use stacks to traverse both trees in parallel, simulating a depth-first traversal. By comparing nodes as we pop them from the stack, we can check for both structural and value equality. This approach avoids recursion and leverages explicit stack management for control over traversal order.
⏰ Time complexity: O(n) — Each node in both trees is pushed and popped from the stack exactly once.
🧺 Space complexity: O(h) — The maximum number of nodes in the stack at any time is the height of the tree (h). In the worst case (skewed tree), this is O(n); for a balanced tree, it is O(log n).