DDSA Solutions

Check if subtree

Advertisement

Intuition

Two binary trees are identical if and only if their inorder traversals — with explicit null markers — match. So checking whether T2 is a subtree of T1 reduces to checking whether T2's inorder serialization appears as a contiguous subsequence inside T1's. That subsequence search is solved in linear time with KMP, turning an O(m×n) brute-force comparison into O(m+n).

Algorithm

  1. 1Run inorder(root1, list1): for each null child insert 0 as a sentinel.
  2. 2Run inorder(root2, list2): same null-marker convention.
  3. 3Build the KMP LPS (Longest Proper Prefix-Suffix) array for list2.
  4. 4KMP-scan list1 with list2 as the pattern; if index j reaches list2.size(), a full match was found.
  5. 5Return true on match, false if the scan exhausts list1.

Example Walkthrough

Input: root1 = [1, 2, 3], root2 = [2]

  1. 1.Inorder(root1): [0, 2, 0, 1, 0, 3, 0] (0 = null marker).
  2. 2.Inorder(root2): [0, 2, 0].
  3. 3.LPS for [0, 2, 0] = [0, 0, 1].
  4. 4.KMP scan: list1[0..2] = [0,2,0] matches list2 fully at j=3.
  5. 5.Match found — root2 is a subtree of root1.

Output: true

Common Pitfalls

  • Omitting null markers makes structurally different trees look identical — e.g., a left-only child and a right-only child with the same value produce the same inorder list without markers.
  • Using 0 as a null sentinel collides with node values that are actually 0; a safer sentinel is a value outside the problem's allowed node-value range.
  • An empty T2 (root2 == null) is always a subtree; the inorder list for null is just [0], and [0] appears in every non-empty tree's serialization.
Check if subtree.java
Java

import java.util.*;

class Node {

    int data;
    Node left;
    Node right;

    Node(int x) {
        data = x;
        left = right = null;
    }
}

// Approach: Serialize both trees via inorder traversal (inserting 0 as a null-node marker),
// then use KMP substring search to check whether root2's inorder sequence appears inside root1's.
// Null markers are essential — without them, different tree shapes can produce identical inorder lists.
// Time: O(m + n) Space: O(m + n)

class Solution {

    public boolean isSubTree(Node root1, Node root2) {
        ArrayList<Integer> list1 = new ArrayList<>();
        ArrayList<Integer> list2 = new ArrayList<>();

        inorder(root1, list1);
        inorder(root2, list2);

        return isSublist(list1, list2);
    }

    public boolean isSublist(ArrayList<Integer> list, ArrayList<Integer> sublist) {
        if (sublist.isEmpty()) {
            return true;
        }
        if (sublist.size() > list.size()) {
            return false;
        }

        // Compute LPS array for the sublist
        int[] lps = computeLPS(sublist);

        int i = 0; // index for list
        int j = 0; // index for sublist

        while (i < list.size()) {
            if (list.get(i).equals(sublist.get(j))) {
                i++;
                j++;
            }

            if (j == sublist.size()) {
                return true; // Found complete match
            } else if (i < list.size() && !list.get(i).equals(sublist.get(j))) {
                if (j != 0) {
                    j = lps[j - 1];
                } else {
                    i++;
                }
            }
        }
        return false;
    }

    private int[] computeLPS(ArrayList<Integer> pattern) {
        int[] lps = new int[pattern.size()];
        int len = 0;
        int i = 1;

        while (i < pattern.size()) {
            if (pattern.get(i).equals(pattern.get(len))) {
                len++;
                lps[i] = len;
                i++;
            } else {
                if (len != 0) {
                    len = lps[len - 1];
                } else {
                    lps[i] = 0;
                    i++;
                }
            }
        }

        return lps;
    }

    public void inorder(Node root, ArrayList<Integer> list) {
        if (root == null) {
            list.add(0);
            return;
        }
        inorder(root.left, list);
        list.add(root.data);
        inorder(root.right, list);
    }
}
Advertisement
Was this solution helpful?