Implement binaryTreeSubtree(root, subRoot) — return a boolean: does the tree rooted at root contain a subtree that is structurally identical to the tree rooted at subRoot? "Identical" means same shape and same values, matched from some node in root all the way down to its leaves. This is the shape of question a code-search tool answers when it asks "does this file contain this exact expression tree?" — a structural match, not a values-somewhere-in-there match.
// A binary tree node. Leaves have left === null and right === null.
type TreeNode = {
val: number;
left: TreeNode | null;
right: TreeNode | null;
};
// root: the tree to search inside (may be null for an empty tree)
// subRoot: the pattern tree to look for (may be null)
// returns: true if some node in root begins a subtree identical to subRoot
function binaryTreeSubtree(
root: TreeNode | null,
subRoot: TreeNode | null
): boolean;
A match must extend from a node in root all the way down: that node's value equals subRoot.val, its left child's whole subtree equals subRoot.left's whole subtree, and the same on the right. A node whose value happens to match but whose children differ is not a match.
// root: subRoot:
// 3 4
// / \ / \
// 4 5 1 2
// / \
// 1 2
const root = {
val: 3,
left: { val: 4, left: { val: 1, left: null, right: null },
right: { val: 2, left: null, right: null } },
right: { val: 5, left: null, right: null },
};
const subRoot = {
val: 4,
left: { val: 1, left: null, right: null },
right: { val: 2, left: null, right: null },
};
binaryTreeSubtree(root, subRoot); // → true (the node 4 and everything below it match exactly)
// Same root, but subRoot now has an extra node under the 1.
// root's node 4 has 1 as a leaf; subRoot's 1 has a left child 0.
// They agree at the top but differ deeper, so this is NOT a match.
const subRoot2 = {
val: 4,
left: { val: 1, left: { val: 0, left: null, right: null }, right: null },
right: { val: 2, left: null, right: null },
};
binaryTreeSubtree(root, subRoot2); // → false (differs at a deep leaf)
subRoot to appear embedded inside root. The matching node's entire subtree — every descendant — must equal subRoot's entire subtree. An embedded fragment that has extra children hanging off it in root is not a subtree match.subRoot returns true. An empty tree is a subtree of every tree (including an empty root) — there is nothing to find, so the search trivially succeeds. This is the documented policy for this question.subRoot against a null root returns false. There is no node to start a match from.root. Finding a node whose value matches subRoot.val is only the start — you still have to verify the full subtree below it. Only the location that matches all the way down counts.===.