Watch 10 video solutions for Construct String with Minimum Cost (Easy), a medium level problem. This walkthrough by Greg Hogg has 123,655 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 <= 20001 <= words.length == costs.length <= 501 <= words[i].length <= target.lengthtarget and words[i] consist only of lowercase English letters.1 <= costs[i] <= 105Problem Overview: You are given a target string and a list of words where each word has an associated cost. The task is to construct the target by concatenating words from the list while minimizing the total cost. Words can only match the target at valid positions, so the core challenge is choosing the cheapest sequence of matches that fully builds the string.
Approach 1: Brute Force Backtracking (Exponential Time, O(2^n) time, O(n) space)
The most direct idea is to try constructing the target from left to right. At every index, iterate through every word and check whether it matches the substring starting at that position. If it matches, recursively attempt to build the rest of the string and add the word's cost. This explores every possible combination of word placements. While conceptually simple, repeated exploration of the same suffix makes this approach exponential and impractical for larger inputs.
Approach 2: Dynamic Programming with Substring Checks (O(n * m * L) time, O(n) space)
Dynamic programming avoids recomputation by storing the minimum cost needed to construct the suffix starting at each index. For position i, iterate over all words and check whether each word matches the substring starting at i. If it does, update dp[i] using cost(word) + dp[i + len(word)]. This eliminates repeated work compared to brute force, but still performs many substring comparisons, especially when the word list is large.
Approach 3: Trie + Memoized DFS (Optimal) (O(n * L) time, O(n + totalTrieNodes) space)
The optimized solution stores all words in a Trie. Starting from each index of the target, traverse the Trie character by character while simultaneously scanning the string. Every time a Trie node marks the end of a word, treat it as a valid cut and recursively compute the cost for the remaining suffix. Use memoization to cache the minimum cost for each starting index so each suffix is solved once. Trie traversal avoids checking every word individually and only follows characters that actually match the target. The recursion behaves like a DFS over valid word boundaries while memoization guarantees efficiency.
Recommended for interviews: The Trie + memoized DFS approach is the expected solution. Brute force demonstrates the baseline idea of exploring word placements, but the optimal approach shows you understand prefix structures and dynamic programming to eliminate redundant work. Interviewers typically look for recognizing overlapping subproblems and using a Trie to efficiently match prefixes.
| Approach | Time | Space | When to Use |
|---|---|---|---|
| Brute Force Backtracking | O(2^n) | O(n) | Conceptual starting point or very small inputs |
| Dynamic Programming with Substring Checks | O(n * m * L) | O(n) | When word list is small and substring checks are cheap |
| Trie + Memoized DFS | O(n * L) | O(n + Trie) | General case with many words and shared prefixes |