Skip to content

LeetCode 617: Merge Two Binary Trees

A recursive tree traversal guide for merging two binary trees node by node.

Problem Restatement

We are given two binary trees: root1 and root2.

We need to merge them into a single binary tree.

The merge rule is:

CaseResult
Both nodes existSum their values
One node is nullUse the non-null node
Both nullResult is null

We return the merged tree as the new root.

The official problem defines merging two binary trees by summing overlapping nodes and using the non-null node when only one exists. (leetcode.com)

Input and Output

Function signature:

def mergeTrees(root1: Optional[TreeNode], root2: Optional[TreeNode]) -> Optional[TreeNode]:
    ...

Input:

ParameterMeaning
root1First binary tree
root2Second binary tree

Output:

TypeMeaning
TreeNodeRoot of merged tree

Example

Tree 1:

    1
   / \
  3   2
 /
5

Tree 2:

    2
   / \
  1   3
   \   \
    4   7

Merged tree:

OperationResult
1 + 23
3 + 14
2 + 35
55
44
77

Result:

      3
     / \
    4   5
   / \   \
  5   4   7

First Thought: Modify One Tree

A simple idea is to merge root2 into root1 directly.

If both nodes exist, we update root1.val.

If only one exists, we attach it.

This avoids creating a new tree.

Key Insight

This is a classic DFS tree recursion problem.

At every pair of nodes:

ConditionAction
both nodes existmerge values
only one existsreturn that node
both nullreturn null

We apply this recursively to left and right children.

Algorithm

For each pair of nodes (n1, n2):

  1. If n1 is null, return n2.
  2. If n2 is null, return n1.
  3. Otherwise:
    • Sum values: n1.val += n2.val
    • Merge left children
    • Merge right children
  4. Return n1 as the merged root.

Implementation

from typing import Optional

class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

class Solution:
    def mergeTrees(
        self,
        root1: Optional[TreeNode],
        root2: Optional[TreeNode]
    ) -> Optional[TreeNode]:

        if not root1:
            return root2

        if not root2:
            return root1

        root1.val += root2.val

        root1.left = self.mergeTrees(root1.left, root2.left)
        root1.right = self.mergeTrees(root1.right, root2.right)

        return root1

Code Explanation

We first handle base cases:

if not root1:
    return root2

if not root2:
    return root1

This means:

CaseMeaning
root1 is nullUse root2 directly
root2 is nullUse root1 directly

If both nodes exist, we merge their values:

root1.val += root2.val

Then we recursively merge the left subtree:

root1.left = self.mergeTrees(root1.left, root2.left)

And the right subtree:

root1.right = self.mergeTrees(root1.right, root2.right)

Finally, we return the updated root1.

Correctness

The algorithm processes both trees in parallel using DFS.

For each pair of nodes at the same position:

CaseBehavior
both nodes existvalues are added
one node missingexisting subtree is reused
both missingrecursion returns null

Because recursion explores left and right subtrees independently, every node in both trees is visited exactly once.

The merge operation is applied exactly once per overlapping node pair, ensuring correct accumulation of values.

Non-overlapping nodes are preserved without modification.

Therefore, the resulting tree correctly represents the merged structure defined by the problem.

Complexity

Let n be the number of nodes in root1, and m be the number of nodes in root2.

MetricValueWhy
TimeO(min(n, m))Each overlapping node pair is visited once
SpaceO(h)Recursion stack depth equals tree height

Worst case space:

Tree ShapeSpace
BalancedO(log n)
SkewedO(n)

Alternative: Create New Tree

We can also build a new tree instead of modifying root1.

class Solution:
    def mergeTrees(
        self,
        root1: Optional[TreeNode],
        root2: Optional[TreeNode]
    ) -> Optional[TreeNode]:

        if not root1 and not root2:
            return None

        val1 = root1.val if root1 else 0
        val2 = root2.val if root2 else 0

        new_root = TreeNode(val1 + val2)

        new_root.left = self.mergeTrees(
            root1.left if root1 else None,
            root2.left if root2 else None
        )

        new_root.right = self.mergeTrees(
            root1.right if root1 else None,
            root2.right if root2 else None
        )

        return new_root

This version avoids mutating inputs but uses slightly more memory.

Testing

def run_tests():
    s = Solution()

    t1 = TreeNode(1,
        TreeNode(3, TreeNode(5)),
        TreeNode(2)
    )

    t2 = TreeNode(2,
        TreeNode(1, None, TreeNode(4)),
        TreeNode(3, None, TreeNode(7))
    )

    merged = s.mergeTrees(t1, t2)

    assert merged.val == 3
    assert merged.left.val == 4
    assert merged.right.val == 5
    assert merged.left.left.val == 5
    assert merged.left.right.val == 4
    assert merged.right.right.val == 7

    t3 = None
    t4 = TreeNode(1)

    assert s.mergeTrees(t3, t4).val == 1

    print("all tests passed")

run_tests()

Test coverage:

CaseWhy
Overlapping treesConfirms value merging
Uneven structureConfirms subtree reuse
One empty treeConfirms base case handling