Smallest String Starting From Leaf in Python

Suppose we have the root of a binary tree, where each node contains a value from 0 to 25, representing the letters 'a' to 'z': a value of 0 represents 'a', a value of 1 represents 'b', and so on. We have to find the lexicographically smallest string that starts at a leaf of this tree and ends at the root.

z(25) b(1) d(3) b(1) d(3) a(0) c(2) Path: a ? d ? z = "adz"

For the tree shown above, the output will be "adz" as the sequence from leaf to root is [0,3,25].

Algorithm

To solve this problem, we use Depth-First Search (DFS) to traverse all paths from root to leaf, then reverse each path to get leaf-to-root strings ?

  • Perform DFS traversal from root to all leaves

  • For each leaf node, construct the string from leaf to root

  • Keep track of the lexicographically smallest string found

  • Use backtracking to explore all possible paths

Implementation

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

def insert(temp, data):
    queue = [temp]
    while queue:
        temp = queue.pop(0)
        if not temp.left:
            temp.left = TreeNode(data) if data is not None else TreeNode(0)
            break
        else:
            queue.append(temp.left)
        if not temp.right:
            temp.right = TreeNode(data) if data is not None else TreeNode(0)
            break
        else:
            queue.append(temp.right)

def make_tree(elements):
    if not elements:
        return None
    tree = TreeNode(elements[0])
    for element in elements[1:]:
        insert(tree, element)
    return tree

class Solution:
    def smallestFromLeaf(self, root):
        self.ans = "~"  # Initialize with largest possible character
        self.dfs(root, [])
        return self.ans
    
    def dfs(self, node, path):
        if node:
            # Add current node's character to path
            path.append(chr(node.data + ord('a')))
            
            # If it's a leaf node, compare the reversed path
            if not node.left and not node.right:
                current_string = ''.join(reversed(path))
                self.ans = min(self.ans, current_string)
                path.pop()
                return
            
            # Recursively traverse left and right subtrees
            self.dfs(node.left, path)
            self.dfs(node.right, path)
            
            # Backtrack: remove current node from path
            path.pop()

# Create the tree and test
root = make_tree([25, 1, 3, 1, 3, 0, 2])
solution = Solution()
result = solution.smallestFromLeaf(root)
print(f"Smallest string from leaf: {result}")
Smallest string from leaf: adz

How It Works

The algorithm works by maintaining a path from root to the current node during DFS traversal. When we reach a leaf node, we reverse this path to get the string from leaf to root and compare it with our current answer.

Step-by-Step Process

# Let's trace through the algorithm with a simple example
class TreeNode:
    def __init__(self, data, left=None, right=None):
        self.data = data
        self.left = left
        self.right = right

# Create a simple tree: root(2) with left(0) and right(1)
root = TreeNode(2)  # 'c'
root.left = TreeNode(0)   # 'a'
root.right = TreeNode(1)  # 'b'

def trace_paths(node, path, paths):
    if node:
        path.append(chr(node.data + ord('a')))
        
        if not node.left and not node.right:
            # Leaf node - record the path from leaf to root
            leaf_to_root = ''.join(reversed(path))
            paths.append(leaf_to_root)
            print(f"Leaf path: {' -> '.join(path)} = {leaf_to_root}")
        
        trace_paths(node.left, path, paths)
        trace_paths(node.right, path, paths)
        path.pop()

paths = []
trace_paths(root, [], paths)
print(f"All paths: {paths}")
print(f"Smallest: {min(paths)}")
Leaf path: c -> a = ac
Leaf path: c -> b = bc
All paths: ['ac', 'bc']
Smallest: ac

Key Points

  • Time Complexity: O(N) where N is the number of nodes, as we visit each node once

  • Space Complexity: O(H) where H is the height of the tree for the recursion stack

  • Backtracking: Essential to explore all paths without interference

  • String Comparison: Python's lexicographical comparison works perfectly for finding the minimum

Conclusion

This solution uses DFS with backtracking to find all leaf-to-root paths, then returns the lexicographically smallest one. The key insight is reversing the root-to-leaf path to get the required leaf-to-root string for comparison.

Updated on: 2026-03-25T08:13:15+05:30

326 Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements