Implement binaryTreeEqual(a, b) that returns whether two binary trees are the same tree: identical in shape AND carrying the same value at every corresponding node. This is the classic LeetCode "Same Tree" problem. Each node is a plain object { val, left, right }, and an absent child or an empty tree is null.
// A binary tree node, or null for an absent child / empty tree.
// type Node = { val: unknown; left: Node | null; right: Node | null };
//
// a: Node | null — the first tree's root.
// b: Node | null — the second tree's root.
// returns: boolean — true only if both trees have the SAME shape AND the
// SAME value at every matching position.
function binaryTreeEqual(a, b): boolean;
// Identical three-node trees → true.
const a = { val: 1, left: { val: 2, left: null, right: null }, right: { val: 3, left: null, right: null } };
const b = { val: 1, left: { val: 2, left: null, right: null }, right: { val: 3, left: null, right: null } };
binaryTreeEqual(a, b); // → true
// Same values, mirrored placement (2 on the left vs. on the right) → false.
const a = { val: 1, left: { val: 2, left: null, right: null }, right: null };
const b = { val: 1, left: null, right: { val: 2, left: null, right: null } };
binaryTreeEqual(a, b); // → false
binaryTreeEqual(null, null) returns true — two missing trees match.null in the other, the trees differ right there.===. Treat node values as primitives compared by strict equality; you do not need to handle objects-as-values.val, left, and right.You'll decide whether two binary trees are the same tree — same shape, same value at every matching spot — by comparing them one pair of positions at a time.
Picture two family trees printed on tracing paper. You lay one over the other and check: is the person at the top the same? Is the child on the left the same? The child on the right? You keep going down until every position lines up — or until you hit the first spot where they don't. Two binary trees are equal when every position matches: the same node is present in both (or absent in both), and where both have a node, the values agree. The function returns a single true/false.
At any single position you're comparing two slots, a and b, and there are only three situations. If both are null, those two missing subtrees match — return true. If exactly one is null, one tree has a node here and the other doesn't, so the shapes already disagree — return false. If both are real nodes, their vals must be equal, and then the same question repeats for the left children and for the right children. That repetition is the recursion: the answer for a node is "values match AND left subtrees equal AND right subtrees equal."
A tempting shortcut: if equality means "same shape and same values," why not just serialize both trees to JSON and compare the strings?
function binaryTreeEqual(a, b) {
return JSON.stringify(a) === JSON.stringify(b);
}
For the exact node shape in this problem this actually passes the tests — JSON.stringify walks the object in a fixed key order and null children serialize as null, so two structurally identical trees produce identical strings. But it's fragile and wasteful. It leans on every node having exactly the keys val, left, right in the same order: the moment a node carries an extra field, or the keys are inserted in a different order, two trees that are equal stringify differently and you get a wrong false. It also builds two potentially huge strings just to throw them away, and it can't compare values with === semantics (a value of 1 and '1' would be allowed to differ correctly here, but you've given up control over that comparison). The structural recursion is barely more code and says exactly what you mean.
function binaryTreeEqual(a, b) {
// Both spots are empty — two missing subtrees match.
if (a === null && b === null) return true;
// Exactly one spot is empty — the shapes already disagree here.
if (a === null || b === null) return false;
// Both are real nodes: their values must match, AND the left subtrees
// must be equal, AND the right subtrees must be equal.
return (
a.val === b.val &&
binaryTreeEqual(a.left, b.left) &&
binaryTreeEqual(a.right, b.right)
);
}
module.exports = { binaryTreeEqual };
The two guards at the top handle the empty cases and — importantly — their order matters. By the time you reach the third return, you've ruled out every null: the first guard caught "both null," the second caught "exactly one null," so both a and b are guaranteed to be real nodes and a.val / a.left are safe to read. The && chain short-circuits: if a.val !== b.val, JavaScript never even looks at the children, and the whole tree resolves to false immediately. Each recursive call asks the same three-case question one level down, so the recursion naturally bottoms out at the leaves (where both children are null).
Trace two trees that match at the root and left child but differ on the right.
a = 1 b = 1
/ \ / \
2 3 2 9
binaryTreeEqual(a, b)
a, b both nodes, 1 === 1 ✓ → recurse left, then right
├─ left: binaryTreeEqual(node 2, node 2)
│ 2 === 2 ✓ → recurse left & right
│ ├─ left: binaryTreeEqual(null, null) → true
│ └─ right: binaryTreeEqual(null, null) → true
│ returns true
└─ right: binaryTreeEqual(node 3, node 9)
3 === 9 ✗ → returns false (children never checked)
root: 1 === 1 && true && false → false
The left subtree fully agrees and returns true. The right subtree fails at the value check — 3 === 9 is false — so that call returns false without recursing further. Back at the root, the && chain is true && true && false, which is false, and the whole comparison reports the trees are not equal.
null. If you write if (a.val !== b.val) first, you crash with "cannot read properties of null" the instant one side is null. Handle the two null cases before you ever read a.val.null is true (a match), one null is false (a mismatch). Collapsing them into a single if (a === null || b === null) return false wrongly reports two empty trees as unequal.|| instead of && — accepts trees that agree on one side and differ on the other. Equality needs the value match and the left subtrees equal and the right subtrees equal.a.left pairs with b.left, a.right with b.right. Cross-comparing left to right is a different question (that's "mirror image," not "same tree").Keep practising the same patterns with a nearby challenge.
No submissions yet
Share your approach and start the discussion.
Implement binaryTreeEqual(a, b) that returns whether two binary trees are the same tree: identical in shape AND carrying the same value at every corresponding node. This is the classic LeetCode "Same Tree" problem. Each node is a plain object { val, left, right }, and an absent child or an empty tree is null.
// A binary tree node, or null for an absent child / empty tree.
// type Node = { val: unknown; left: Node | null; right: Node | null };
//
// a: Node | null — the first tree's root.
// b: Node | null — the second tree's root.
// returns: boolean — true only if both trees have the SAME shape AND the
// SAME value at every matching position.
function binaryTreeEqual(a, b): boolean;
// Identical three-node trees → true.
const a = { val: 1, left: { val: 2, left: null, right: null }, right: { val: 3, left: null, right: null } };
const b = { val: 1, left: { val: 2, left: null, right: null }, right: { val: 3, left: null, right: null } };
binaryTreeEqual(a, b); // → true
// Same values, mirrored placement (2 on the left vs. on the right) → false.
const a = { val: 1, left: { val: 2, left: null, right: null }, right: null };
const b = { val: 1, left: null, right: { val: 2, left: null, right: null } };
binaryTreeEqual(a, b); // → false
binaryTreeEqual(null, null) returns true — two missing trees match.null in the other, the trees differ right there.===. Treat node values as primitives compared by strict equality; you do not need to handle objects-as-values.val, left, and right.You'll decide whether two binary trees are the same tree — same shape, same value at every matching spot — by comparing them one pair of positions at a time.
Picture two family trees printed on tracing paper. You lay one over the other and check: is the person at the top the same? Is the child on the left the same? The child on the right? You keep going down until every position lines up — or until you hit the first spot where they don't. Two binary trees are equal when every position matches: the same node is present in both (or absent in both), and where both have a node, the values agree. The function returns a single true/false.
At any single position you're comparing two slots, a and b, and there are only three situations. If both are null, those two missing subtrees match — return true. If exactly one is null, one tree has a node here and the other doesn't, so the shapes already disagree — return false. If both are real nodes, their vals must be equal, and then the same question repeats for the left children and for the right children. That repetition is the recursion: the answer for a node is "values match AND left subtrees equal AND right subtrees equal."
A tempting shortcut: if equality means "same shape and same values," why not just serialize both trees to JSON and compare the strings?
function binaryTreeEqual(a, b) {
return JSON.stringify(a) === JSON.stringify(b);
}
For the exact node shape in this problem this actually passes the tests — JSON.stringify walks the object in a fixed key order and null children serialize as null, so two structurally identical trees produce identical strings. But it's fragile and wasteful. It leans on every node having exactly the keys val, left, right in the same order: the moment a node carries an extra field, or the keys are inserted in a different order, two trees that are equal stringify differently and you get a wrong false. It also builds two potentially huge strings just to throw them away, and it can't compare values with === semantics (a value of 1 and '1' would be allowed to differ correctly here, but you've given up control over that comparison). The structural recursion is barely more code and says exactly what you mean.
function binaryTreeEqual(a, b) {
// Both spots are empty — two missing subtrees match.
if (a === null && b === null) return true;
// Exactly one spot is empty — the shapes already disagree here.
if (a === null || b === null) return false;
// Both are real nodes: their values must match, AND the left subtrees
// must be equal, AND the right subtrees must be equal.
return (
a.val === b.val &&
binaryTreeEqual(a.left, b.left) &&
binaryTreeEqual(a.right, b.right)
);
}
module.exports = { binaryTreeEqual };
The two guards at the top handle the empty cases and — importantly — their order matters. By the time you reach the third return, you've ruled out every null: the first guard caught "both null," the second caught "exactly one null," so both a and b are guaranteed to be real nodes and a.val / a.left are safe to read. The && chain short-circuits: if a.val !== b.val, JavaScript never even looks at the children, and the whole tree resolves to false immediately. Each recursive call asks the same three-case question one level down, so the recursion naturally bottoms out at the leaves (where both children are null).
Trace two trees that match at the root and left child but differ on the right.
a = 1 b = 1
/ \ / \
2 3 2 9
binaryTreeEqual(a, b)
a, b both nodes, 1 === 1 ✓ → recurse left, then right
├─ left: binaryTreeEqual(node 2, node 2)
│ 2 === 2 ✓ → recurse left & right
│ ├─ left: binaryTreeEqual(null, null) → true
│ └─ right: binaryTreeEqual(null, null) → true
│ returns true
└─ right: binaryTreeEqual(node 3, node 9)
3 === 9 ✗ → returns false (children never checked)
root: 1 === 1 && true && false → false
The left subtree fully agrees and returns true. The right subtree fails at the value check — 3 === 9 is false — so that call returns false without recursing further. Back at the root, the && chain is true && true && false, which is false, and the whole comparison reports the trees are not equal.
null. If you write if (a.val !== b.val) first, you crash with "cannot read properties of null" the instant one side is null. Handle the two null cases before you ever read a.val.null is true (a match), one null is false (a mismatch). Collapsing them into a single if (a === null || b === null) return false wrongly reports two empty trees as unequal.|| instead of && — accepts trees that agree on one side and differ on the other. Equality needs the value match and the left subtrees equal and the right subtrees equal.a.left pairs with b.left, a.right with b.right. Cross-comparing left to right is a different question (that's "mirror image," not "same tree").Keep practising the same patterns with a nearby challenge.
No submissions yet
Share your approach and start the discussion.