Skip to main content

Apply Substitutions - Solution & Explanation

MediumPremiumFree on FleetCodeArrayHash TableStringDepth-First Search10 min readAsked at: Google
Practice this problem

Problem Statement

You are given a replacements mapping and a text string that may contain placeholders formatted as %var%, where each var corresponds to a key in the replacements mapping. Each replacement value may itself contain one or more such placeholders. Each placeholder is replaced by the value associated with its corresponding replacement key.

Return the fully substituted text string which does not contain any placeholders.

 

Example 1:

Input: replacements = [["A","abc"],["B","def"]], text = "%A%_%B%"

Output: "abc_def"

Explanation:

  • The mapping associates "A" with "abc" and "B" with "def".
  • Replace %A% with "abc" and %B% with "def" in the text.
  • The final text becomes "abc_def".

Example 2:

Input: replacements = [["A","bce"],["B","ace"],["C","abc%B%"]], text = "%A%_%B%_%C%"

Output: "bce_ace_abcace"

Explanation:

  • The mapping associates "A" with "bce", "B" with "ace", and "C" with "abc%B%".
  • Replace %A% with "bce" and %B% with "ace" in the text.
  • Then, for %C%, substitute %B% in "abc%B%" with "ace" to obtain "abcace".
  • The final text becomes "bce_ace_abcace".

 

Constraints:

  • 1 <= replacements.length <= 10
  • Each element of replacements is a two-element list [key, value], where:
    • key is a single uppercase English letter.
    • value is a non-empty string of at most 8 characters that may contain zero or more placeholders formatted as %<key>%.
  • All replacement keys are unique.
  • The text string is formed by concatenating all key placeholders (formatted as %<key>%) randomly from the replacements mapping, separated by underscores.
  • text.length == 4 * replacements.length - 1
  • Every placeholder in the text or in any replacement value corresponds to a key in the replacements mapping.
  • There are no cyclic dependencies between replacement keys.

Approach Overview

Problem Overview: You receive a set of substitution rules where a key maps to a string that may reference other keys. Applying substitutions requires expanding each key until only final characters remain. Dependencies between keys form a directed graph, so the main challenge is resolving them in the correct order while avoiding repeated work.

Approach 1: Hash Table + Recursion (DFS with Memoization) (Time: O(n + L), Space: O(n + L))

Store every substitution rule in a hash table so you can resolve a key in constant time. When expanding a key, recursively resolve every referenced token inside its string. This naturally forms a graph where nodes are variables and edges represent dependencies. A depth‑first traversal expands dependencies first, then builds the final resolved string for the current key.

Memoization prevents recomputing the same substitution multiple times. Once a key is fully expanded, cache the result in the hash map. Future lookups return instantly. This converts repeated expansions from exponential behavior into linear work relative to the total size of all strings.

Cycle detection is handled with a recursion stack or visiting set. If a key is encountered while it is still being processed, the rules contain a circular dependency. In most implementations you either reject the input or skip further expansion. Because each key is processed once and each character is appended once, the runtime stays O(n + L), where n is the number of rules and L is the total length of all expanded strings.

Approach 2: Graph + Topological Sort (Time: O(n + L), Space: O(n + L))

You can model the substitutions explicitly as a dependency graph and resolve them in topological order. First build adjacency lists showing which keys depend on which other keys. Then compute in‑degrees and run a BFS‑style topological sort. Keys with no dependencies resolve immediately because their substitution strings contain only literals.

As each node is processed, replace references in dependent nodes with the resolved value and reduce their in‑degree. Once a dependent node has no remaining unresolved references, it becomes eligible for processing. This approach avoids recursion and works well when the dependency graph is large or when iterative solutions are preferred.

Recommended for interviews: The Hash Table + DFS approach is typically expected. It is concise, naturally expresses dependency resolution, and shows familiarity with memoization and graph traversal. Mentioning the topological sort alternative demonstrates deeper understanding of dependency graphs and how DFS and BFS can both solve the same problem.

Solution

We use a hash table d to store the substitution mapping, and then define a function dfs to recursively replace the placeholders in the string.

The execution logic of the function dfs is as follows:

  1. Find the starting position i of the first placeholder in the string s. If not found, return s;
  2. Find the ending position j of the first placeholder in the string s. If not found, return s;
  3. Extract the key of the placeholder, and then recursively replace the value of the placeholder d[key];
  4. Return the replaced string.

In the main function, we call the dfs function, pass in the text string text, and return the result.

The time complexity is O(m + n times L), and the space complexity is O(m + n times L). Where m is the length of the substitution mapping, and n and L are the length of the text string and the average length of the placeholders, respectively.

Code

Python

Java

C++

Go

TypeScript

Try this approach in the editor →

Detailed Complexity Analysis

ApproachTimeSpaceWhen to Use
Hash Table + DFS RecursionO(n + L)O(n + L)General case. Clean recursive solution with memoization to resolve dependencies.
Graph + Topological Sort (BFS)O(n + L)O(n + L)Useful when avoiding recursion or when explicitly modeling dependency graphs.

Video Solution

leetcode 3481 Apply Substitutions | string replace method, Kahn's alg for topo sorting • Code-Yao • 1,401 views views

Watch 1 more video solutions →

Frequently Asked Questions

Is Apply Substitutions easy or hard?
Apply Substitutions is generally considered a medium difficulty problem. The tricky part is recognizing that substitution rules create a dependency graph and that memoized DFS or topological sorting efficiently resolves the chain.
Apply Substitutions Python/Java solution
Python, Java, C++, Go, and TypeScript implementations typically use a dictionary or map plus a recursive DFS function. The DFS resolves dependencies and stores computed results in a memo map to avoid repeated expansion.
How to solve Apply Substitutions in O(n)?
Build a hash map from variable to substitution string, then run DFS to expand each variable. During recursion, resolve referenced variables first and cache their results. Because each variable and character is processed once, the total runtime becomes O(n + L).
What is the best approach for Apply Substitutions?
The most practical approach uses a hash table with DFS recursion and memoization. Each substitution rule becomes a node in a dependency graph, and DFS resolves dependencies before building the final string. Memoization ensures every key is expanded only once, giving O(n + L) time where L is the total expanded string length.
Is Apply Substitutions asked at Google/Amazon/Meta?
Dependency resolution and substitution expansion problems frequently appear in interviews at companies like Google, Amazon, and Meta. Variants often test graph modeling, cycle detection, and DFS with memoization.
What data structure is used in Apply Substitutions?
The core structure is a hash table mapping each variable to its substitution string. Internally the relationships form a directed graph, which is traversed using depth‑first search or resolved using topological sorting.
What is the time complexity of Apply Substitutions?
The optimal solution runs in O(n + L) time. Each substitution rule is processed once and every character in the final expanded strings is appended once. Memoization prevents repeated recomputation of previously resolved keys.

Ready to solve this problem?

Practice Apply Substitutions with our built-in code editor and test cases.

Practice on FleetCode