AlgoMaster Logo

Subtree of Another Tree

easyFrequency8 min readUpdated June 23, 2026

Understanding the Problem

We have two binary trees. We need to determine whether subRoot appears somewhere inside root as a complete subtree. The word "complete" matters here. It is not enough for subRoot to match a portion of some subtree in root. The matching subtree must include every descendant, all the way down to the leaves.

If root has a node with value 4 whose children are 1 and 2, and subRoot is that same structure (4 with children 1 and 2, both leaves), then we have a match. But if node 2 in root has an extra child that subRoot lacks, it is not a match, because the subtree rooted at 4 in root is no longer identical to subRoot.

This problem splits into two sub-tasks: find nodes in root that could be the starting point of a match, and verify whether the subtree rooted at that node is structurally identical to subRoot.

Key Constraints:

  • 1 <= number of nodes in root <= 2000: The root tree is small, so an O(m * n) brute force fits comfortably within time limits (about 2 million node comparisons in the worst case).
  • 1 <= number of nodes in subRoot <= 1000: The subtree to match can be up to half the size of the main tree.
  • -10^4 <= node values <= 10^4: Values can be negative. Serialization approaches have to delimit values so that a negative sign or multi-digit number cannot be misread, and hashing approaches accumulate products that exceed 32-bit range, so the hash must be stored in a 64-bit integer.

Approach 1: DFS with Same Tree Check

Intuition

Visit every node in root, and at each node, check whether the subtree rooted there is identical to subRoot. If any node passes, return true. If the traversal finishes without a match, return false.

Checking whether two trees are identical is a recursive problem on its own. Two trees are the same when their root values match, their left subtrees are the same, and their right subtrees are the same. Two null trees also count as the same.

The solution is two recursive functions layered together: one that traverses root looking for candidate match points, and a helper that verifies a match by comparing two trees node by node.

Algorithm

  1. If root is null, return false (there's no subtree to match against).
  2. Check if the tree rooted at root is identical to subRoot using a helper function.
  3. If it is, return true.
  4. Otherwise, recursively check whether subRoot is a subtree of root.left or root.right.
  5. The helper function isSameTree compares two trees: if both are null, return true. If one is null or values differ, return false. Otherwise, recursively compare left and right children.

Example Walkthrough

root
1Start at root (3). Call isSameTree(3, subRoot=4)
3check4125
subRoot
1subRoot to find: [4, 1, 2]
412
1/5

Code

This brute force repeats partial comparisons at many nodes. The next approach reframes the problem as substring matching: serialize each tree into a string, then check whether one string contains the other.

Approach 2: Tree Serialization with String Matching

Intuition

Convert both trees into strings, then check whether one string contains the other. If we serialize both trees with preorder traversal, including markers for null nodes, then subRoot is a subtree of root if and only if the serialized subRoot appears as a substring of the serialized root.

The serialization needs care. Concatenating raw values creates ambiguity: a node with value 12 would look the same as a node 1 followed by a node 2, and a node with value 2 could match the tail of value 12. We need a delimiter before each value and an explicit marker for null children, so that the string encodes both the values and the shape of the tree without collisions.

Algorithm

  1. Serialize root into a string using preorder traversal. For each node, append a delimiter followed by the node's value. For null nodes, append a delimiter followed by a null marker (e.g., #).
  2. Serialize subRoot the same way.
  3. Check if the serialized subRoot is a substring of the serialized root.
  4. If yes, return true. Otherwise, return false.

Example Walkthrough

rootStr
1Serialize root via preorder: visit 3
0
,
1
3
node 3
subStr
1Serialize subRoot via preorder: visit 4
0
,
1
4
node 4
1/5

Code

The serialization approach builds full strings for both trees and relies on substring search. The next approach avoids the strings entirely: it gives each subtree a hash computed from its structure, so comparing two subtrees becomes a single integer comparison.

Approach 3: Tree Hashing (Merkle Hash)

Intuition

This approach borrows the idea behind Merkle trees, used in Git, blockchains, and file systems. Assign each subtree a hash computed from its structure. A leaf's hash depends on its value. An internal node's hash depends on its value combined with the hashes of its left and right children. Two subtrees with the same structure and values produce the same hash, because the hash is built bottom-up from identical inputs at every level.

We compute the hash for every subtree in root and the hash for subRoot, then check whether subRoot's hash appears at any node in root. Each hash combines a node value with two already-computed child hashes, so it costs O(1) per node and O(m + n) overall.

The complication is hash collisions. Two different trees can produce the same hash. When a hash matches, we run a full isSameTree comparison to confirm the match is real. Because that confirmation only runs on the rare hash matches, it does not change the expected running time.

Algorithm

  1. Compute the hash of subRoot by recursively hashing its tree structure.
  2. Traverse root and compute the hash of every subtree.
  3. At each node in root, check if the subtree hash matches subRoot's hash.
  4. If a hash match is found, do a full isSameTree check to rule out hash collisions.
  5. Return true if a confirmed match is found, false otherwise.

Example Walkthrough

root
1Start hashing bottom-up. Compute leaf hashes first.
341h(1)2h(2)5
subRoot
1Compute subRoot hash bottom-up. Start with leaves.
41h(1)2h(2)
1/5

Code