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] <= 104In this approach, we use dynamic programming with memoization to minimize the cost of building the target string by selecting parts of words. We define a dp function that represents the minimum cost to build the substring of the target from a starting index to the end of the string. This function checks possible word matches at different starting positions and calculates the cost recursively.
The Python solution uses a recursive dynamic programming approach, utilizing memoization to store results of previously calculated indices to minimize recomputation. The dp function computes the minimal cost required to construct the target string from the current index to the end. It iterates over all words to see if they match the current segment of the target string. If they match, it calculates the cost recursively for the rest of the string. The base case occurs when the index equals the target's length, returning zero cost because no additional construction is needed.
Time Complexity: O(N * M * L), where N is the length of the target string, M is the number of words, and L is the average length of a word. Space Complexity: O(N), where N is the length of the target string due to memoization.
This approach structures the solution using a bottom-up dynamic programming table (or list) that builds from the smallest subproblem to the full solution. The idea is to fill a dp array where each entry dp[i] represents the minimum cost to build the target's substring from index 0 to i. The solution iteratively checks each word and updates the dp array whenever a word's substring matches a segment of the target starting from an earlier index.
The Java solution uses a bottom-up dynamic programming approach. It initializes a dp array where dp[i] is the minimum cost to reach the ith character of the target. It iteratively updates this array using matching words from the 'words' array to segments of the target. Each iteration checks if a word can extend the current prefix of the target and updates the dp array accordingly. If the whole target string can be constructed, it returns dp[n] as the minimum cost, otherwise, it returns -1.
Time Complexity: O(N * M * L), where N is the length of the target string, M is the number of words, and L is the average length of a word. Space Complexity: O(N), where N is the length of the target string due to the dp array.
This approach leverages dynamic programming to solve the problem by matching prefixes of the target string with dictionary words.
The main idea is to maintain a dp array where dp[i] represents the minimum cost to form the first i characters of the target string. We iterate over each character of the target, and for each position, we attempt to match it with every possible word from the words array. If a word matches a substring of the target beginning at position i, we update dp[i + len(word)] to be the minimum of its current value and dp[i] + cost associated with the word.
The challenge in this approach is efficiently verifying matches between words in the words array and substrings in the target string.
The C solution uses dynamic programming to maintain the minimum cost to form up to each length of the target string. We initialize a dp array with infinity (or a very large value), indicating that those lengths are unreachable initially. At dp[0], we set it to 0 because the cost to form an empty string is zero.
We then iterate over the dp array, updating each entry by attempting to extend it with each word in the words array. If a word matches a substring starting from the current dp index in the target, we update the corresponding dp value to the minimum cost necessary to reach that position using this word or others before it.
Using constraints wisely helps ensure optimal run-time even with relatively longer strings.
C++
Java
Python
C#
JavaScript
Time Complexity: O(T * W * L), where T is the length of the target, W is the size of the words array, and L is the average length of words.
Space Complexity: O(T), for storing the dynamic programming array.
This approach employs backtracking enhanced with memoization to solve subproblems efficiently by caching previously computed results.
The idea here is to explore forming the target string starting from each index using a recursive backtracking function. We attempt to match every word from the words array at the current starting index. If a match is found, the function is recursively called to find the minimum cost from the end of this match to the end of the target.
Memoization ensures that for each starting index, we do not recompute previously explored minimal costs, thus reducing computational overhead.
The C solution uses a recursion function with memoization to attempt constructing the target string starting from each index. The memo array stores the minimum cost required for substrings beginning at various indexes, preventing redundant computations.
The recursion checks each word in words[] against the current index in target, and if found, recurs into forming the rest of the string. Updating the memoization on returning from recursion ensures efficient caching.
C++
Java
Python
C#
JavaScript
Time Complexity: O(T * W * L), where T is the length of the target, W is the number of words, L is the average length of words. Different due to recursion depth and cache misses.
Space Complexity: O(T), due to memo array storage.
| Approach | Complexity |
|---|---|
| Dynamic Programming - Top-Down with Memoization | Time Complexity: O(N * M * L), where N is the length of the target string, M is the number of words, and L is the average length of a word. Space Complexity: O(N), where N is the length of the target string due to memoization. |
| Bottom-Up Dynamic Programming | Time Complexity: O(N * M * L), where N is the length of the target string, M is the number of words, and L is the average length of a word. Space Complexity: O(N), where N is the length of the target string due to the dp array. |
| Approach 1: Dynamic Programming with Word Matching | Time Complexity: O(T * W * L), where T is the length of the target, W is the size of the words array, and L is the average length of words. Space Complexity: O(T), for storing the dynamic programming array. |
| Approach 2: Backtracking with Memoization | Time Complexity: O(T * W * L), where T is the length of the target, W is the number of words, L is the average length of words. Different due to recursion depth and cache misses. Space Complexity: O(T), due to memo array storage. |
Prim's Algorithm - Minimum Spanning Tree - Min Cost to Connect all Points - Leetcode 1584 - Python • NeetCode • 115,027 views views
Watch 9 more video solutions →Practice Construct String with Minimum Cost with our built-in code editor and test cases.
Practice on FleetCode