↓Skip to main content
  1. LeetCode/

LeetCode 652: Find Duplicate Subtrees

·2 mins· ·
LeetCode Medium Hash-Table Tree Depth-First-Search Binary-Tree
Wei Yi Chung
Author
Wei Yi Chung
Working at the contributing of open source, distributed systems, and data engineering.
Table of Contents

Meta Data
#

Difficulty: medium First Attempt: 2026-10-26

  • Submissions: Accepted ×2

Approach
#

Two subtrees are identical exactly when their encodings are equal. Do a post-order DFS (Tree Template 1): get the left and right encodings first, build this node’s encoding, and count it in a hash map (Hash Table Template 5, normalize then use as a key). When an encoding appears for the second time, add the node to the answer; later occurrences are ignored so nothing is reported twice.

The encoding must identify the structure uniquely, so null children are included.

My Attempts
#

Both submissions passed on the first try:

  1. 10-26: the encoding was the string f"{val},{left},{right}" with # for null.
  2. 10-27: mapped (val, left id, right id) to an integer id instead, so the strings do not keep growing.

Solution
#

class Solution:
    def findDuplicateSubtrees(self, root: Optional[TreeNode]) -> List[Optional[TreeNode]]:
        tree_id = {}
        count = defaultdict(int)
        res = []

        def post(node):
            if not node:
                return 0
            key = (node.val, post(node.left), post(node.right))
            if key not in tree_id:
                tree_id[key] = len(tree_id) + 1
            uid = tree_id[key]
            count[uid] += 1
            if count[uid] == 2:
                res.append(node)
            return uid

        post(root)
        return res

Complexity
#

EncodingTime
Stringworst O(n^2): each node’s string is as long as its subtree
(val, left id, right id) → idO(n): each key is a fixed-size tuple

Space is O(n) for both.

Mistakes to Avoid
#

  • Add the node on == 2, not >= 2, or the same shape is reported many times.
  • In-order collides even with null markers: [0,0] and [0,null,0] both give #,0,#,0,#. Use pre-order or post-order.

Interview Explanation
#

I encode every subtree in a post-order DFS, including nulls, count encodings in a hash map, and add a node when its encoding appears the second time. String encodings are O(n^2) in the worst case, so I map (value, left id, right id) to an integer id; each node then does constant work and the total is O(n).

Related

LeetCode 314: Binary Tree Vertical Order Traversal
·2 mins
LeetCode Medium Hash-Table Tree Depth-First-Search Breadth-First-Search Sorting Binary-Tree
LeetCode 314 note: BFS with a column index; BFS is what guarantees top-to-bottom within a column and left-to-right within a row
LeetCode 449: Serialize and Deserialize BST
·2 mins
LeetCode Medium String Tree Depth-First-Search Breadth-First-Search Design Binary-Search-Tree Binary-Tree
LeetCode 449 note: for a BST, pre-order without null markers is enough; deserialize recursively with bounds in O(n)
LeetCode 99: Recover Binary Search Tree
·2 mins
LeetCode Medium Tree Depth-First-Search Binary-Search-Tree Binary-Tree
LeetCode 99 note: find the inversions in the in-order sequence: the earlier node of the first inversion and the later node of the last one were swapped
LeetCode 1372: Longest ZigZag Path in a Binary Tree
·2 mins
LeetCode Medium Dynamic-Programming Tree Depth-First-Search Binary-Tree Dp-on-Trees
LeetCode 1372 note: each node returns two values, the longest zigzag starting left and starting right; going left extends the left child’s start-right value
LeetCode 515: Find Largest Value in Each Tree Row
·1 min
LeetCode Medium Tree Depth-First-Search Breadth-First-Search Binary-Tree
LeetCode 515 note: BFS level order, taking the maximum of each level; start from -inf
LeetCode 687: Longest Univalue Path
·2 mins
LeetCode Medium Tree Depth-First-Search Binary-Tree Dp-on-Trees
LeetCode 687 note: DFS returns the longest same-value downward chain in edges, and each node updates the answer with left + right