Watch 8 video solutions for Construct String with Minimum Cost, a hard level problem involving Array, String, Dynamic Programming. This walkthrough by Aryan Mittal has 3,977 views views. Want to try solving it yourself? Practice on FleetCode or read the detailed text solution.
You are given a string target, an array of strings words, and an integer array costs, both arrays of the same length.
Imagine an empty string s.
You can perform the following operation any number of times (including zero):
i in the range [0, words.length - 1].words[i] to s.costs[i].Return the minimum cost to make s equal to target. If it's not possible, return -1.
Example 1:
Input: target = "abcdef", words = ["abdef","abc","d","def","ef"], costs = [100,1,1,10,5]
Output: 7
Explanation:
The minimum cost can be achieved by performing the following operations:
"abc" to s at a cost of 1, resulting in s = "abc"."d" to s at a cost of 1, resulting in s = "abcd"."ef" to s at a cost of 5, resulting in s = "abcdef".Example 2:
Input: target = "aaaa", words = ["z","zz","zzz"], costs = [1,10,100]
Output: -1
Explanation:
It is impossible to make s equal to target, so we return -1.
Constraints:
1 <= target.length <= 5 * 1041 <= words.length == costs.length <= 5 * 1041 <= words[i].length <= target.lengthwords[i].length is less than or equal to 5 * 104.target and words[i] consist only of lowercase English letters.1 <= costs[i] <= 104Problem Overview: You are given a target string and a list of words where each word has an associated cost. The goal is to construct the entire target string by concatenating these words so that the total cost is minimized. Each word can be used multiple times, but it must exactly match the portion of the target where it is placed.
Approach 1: Backtracking with Memoization (Exponential → O(n * m * L))
Start from index 0 in the target and recursively try every word that matches the current position. If a word matches, move the pointer forward by its length and add its cost. Without optimization this explores an exponential number of combinations. Memoization stores the minimum cost for each starting index so repeated states are computed once. Time complexity becomes roughly O(n * m * L), where n is the target length, m the number of words, and L the average word length. Space complexity is O(n) for recursion and memo storage.
Approach 2: Dynamic Programming with Word Matching (O(n * m * L))
Define dp[i] as the minimum cost required to construct the prefix target[0..i). Initialize dp[0] = 0. For every position i, iterate through the word list and check whether a word matches the substring starting at i. If it matches, update dp[i + len(word)] = min(dp[i + len(word)], dp[i] + cost). This transforms the search into a forward state transition similar to classic Dynamic Programming. Time complexity is O(n * m * L) due to substring comparisons. Space complexity is O(n).
Approach 3: Top-Down Dynamic Programming with Memoization (O(n * m * L))
This version expresses the same recurrence using recursion. The function dfs(i) returns the minimum cost to build the suffix starting at index i. For every word that matches target[i : i + len(word)], recursively compute dfs(i + len(word)) and add the cost. Memoization avoids recomputing states. The algorithm still performs substring checks, so the complexity remains O(n * m * L) with O(n) space. The approach fits naturally when reasoning about suffix construction and is common in problems combining String processing with Dynamic Programming.
Approach 4: Optimized Matching with Suffix Structures (Up to O(n log n + matches))
When the word list is large, repeated substring comparisons dominate runtime. Preprocessing the target using structures like a Suffix Array, trie, or hashing allows faster substring checks. Instead of scanning every word at every position, you query which words match the current suffix and only transition those states. The DP structure stays the same but matching becomes significantly faster for large datasets.
Recommended for interviews: The bottom-up dynamic programming solution with word matching is usually expected. It clearly shows you understand state transitions and optimal substructure. Mentioning memoized recursion demonstrates the same idea from another direction, while discussing suffix-based optimization shows awareness of scaling constraints for large inputs.
| Approach | Time | Space | When to Use |
|---|---|---|---|
| Backtracking with Memoization | O(n * m * L) | O(n) | When exploring combinations conceptually before converting to iterative DP |
| Top-Down Dynamic Programming | O(n * m * L) | O(n) | Natural recursive reasoning for suffix construction |
| Bottom-Up Dynamic Programming | O(n * m * L) | O(n) | Standard interview solution and easiest to implement iteratively |
| DP with Optimized Matching (Suffix Array/Trie) | O(n log n + matches) | O(n + totalWordLength) | Large word lists where repeated substring comparisons are expensive |