Number of Ways to Form a Target String Given a Dictionary - Video Solutions
Number of Ways to Form a Target String Given a Dictionary | Recur | Memo | Leetcode 1639 | MIK
Number of Ways to Form a Target String Given a Dictionary - Video Solution
Watch 10 video solutions for Number of Ways to Form a Target String Given a Dictionary, a hard level problem involving Array, String, Dynamic Programming. This walkthrough by codestorywithMIK has 14,892 views views. Want to try solving it yourself? Practice on FleetCode or read the detailed text solution.
Problem Statement
You are given a list of strings of the same length words and a string target.
Your task is to form target using the given words under the following rules:
targetshould be formed from left to right.- To form the
ithcharacter (0-indexed) oftarget, you can choose thekthcharacter of thejthstring inwordsiftarget[i] = words[j][k]. - Once you use the
kthcharacter of thejthstring ofwords, you can no longer use thexthcharacter of any string inwordswherex <= k. In other words, all characters to the left of or at indexkbecome unusuable for every string. - Repeat the process until you form the string
target.
Notice that you can use multiple characters from the same string in words provided the conditions above are met.
Return the number of ways to form target from words. Since the answer may be too large, return it modulo 109 + 7.
Example 1:
Input: words = ["acca","bbbb","caca"], target = "aba"
Output: 6
Explanation: There are 6 ways to form target.
"aba" -> index 0 ("acca"), index 1 ("bbbb"), index 3 ("caca")
"aba" -> index 0 ("acca"), index 2 ("bbbb"), index 3 ("caca")
"aba" -> index 0 ("acca"), index 1 ("bbbb"), index 3 ("acca")
"aba" -> index 0 ("acca"), index 2 ("bbbb"), index 3 ("acca")
"aba" -> index 1 ("caca"), index 2 ("bbbb"), index 3 ("acca")
"aba" -> index 1 ("caca"), index 2 ("bbbb"), index 3 ("caca")
Example 2:
Input: words = ["abba","baab"], target = "bab"
Output: 4
Explanation: There are 4 ways to form target.
"bab" -> index 0 ("baab"), index 1 ("baab"), index 2 ("abba")
"bab" -> index 0 ("baab"), index 1 ("baab"), index 3 ("baab")
"bab" -> index 0 ("baab"), index 2 ("baab"), index 3 ("baab")
"bab" -> index 1 ("abba"), index 2 ("baab"), index 3 ("baab")
Constraints:
1 <= words.length <= 10001 <= words[i].length <= 1000- All strings in
wordshave the same length. 1 <= target.length <= 1000words[i]andtargetcontain only lowercase English letters.
Approach Overview
Problem Overview: You are given a list of equal-length words and a target string. Characters must be chosen column by column across the dictionary to build the target. Once you move past a column, you cannot reuse earlier columns. The task is to count how many distinct ways the target can be formed.
Approach 1: Memoization with Recursive Choices (Time: O(m * t + n * m), Space: O(m * t))
This approach models the problem as a recursive decision process. At each step you decide whether to use the current column to match the next target character or skip the column entirely. A memoization table caches states defined by (targetIndex, columnIndex) so repeated subproblems are avoided. To make matching efficient, you precompute how many times each character appears in every column of the dictionary. This converts each recursive step into a constant-time lookup rather than scanning all words.
The recurrence multiplies the number of ways a column can supply the required character with the number of ways to build the remaining suffix. Skipping the column moves to the next column without advancing the target index. This turns an exponential brute force search into a manageable dynamic programming problem.
Approach 2: Dynamic Programming with Character Frequency Table (Time: O(n * m + m * t), Space: O(t))
This is the optimized bottom-up solution. First compute a frequency table where freq[c][j] stores how many words contain character c at column j. Building this table costs O(n * m), where n is the number of words and m is the word length.
Then use dynamic programming where dp[i] represents the number of ways to build the first i characters of the target. Iterate through dictionary columns from left to right. For each column, update the DP array backwards so previously computed states are not overwritten. If the column contains the needed character, multiply the frequency by the number of ways to form the previous prefix. This effectively counts how many valid column selections produce each prefix of the target.
The backward update is the key insight: it preserves earlier DP states and ensures each column contributes only once per target position. The result is stored in dp[targetLength]. This solution is efficient because it compresses the 2D DP state into a single array while still respecting column order.
Recommended for interviews: The dynamic programming solution with a character frequency table is what most interviewers expect. It demonstrates strong understanding of dynamic programming, efficient preprocessing with arrays, and careful iteration over string positions. The memoization approach is useful to explain first because it shows the natural recurrence before optimizing to the iterative DP.
Complexity Analysis
| Approach | Time | Space | When to Use |
|---|---|---|---|
| Memoization with Recursive Choices | O(n*m + m*t) | O(m*t) | When deriving the recurrence or explaining the DP state during interviews |
| Dynamic Programming with Character Frequency Table | O(n*m + m*t) | O(t) | Optimal solution for large inputs and production-quality implementations |