1639. Number of Ways to Form a Target String Given a Dictionary
Difficulty: Hard
Topics: Array, String, Dynamic Programming
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 in words iftarget[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 <= 1000-
words[i]andtargetcontain only lowercase English letters.
Hint:
- For each index i, store the frequency of each character in the
ithrow. - Use dynamic programing to calculate the number of ways to get the target string using the frequency array.
Solution:
The problem requires finding the number of ways to form a target string from a dictionary of words, following specific rules about character usage. This is a combinatorial problem that can be solved efficiently using Dynamic Programming (DP) and preprocessing character frequencies.
Key Points
-
Constraints:
- Words are of the same length.
- Characters in words can only be used in a left-to-right manner.
-
Challenges:
- Efficiently counting ways to form
targetdue to large constraints. - Avoid recomputation with memoization.
- Efficiently counting ways to form
-
Modulo:
- Since the result can be large, all calculations are done modulo
109 + 7.
- Since the result can be large, all calculations are done modulo
Approach
The solution uses:
-
Preprocessing:
- Count the frequency of each character at every position across all words.
-
Dynamic Programming:
- Use a 2D DP table to calculate the number of ways to form the
targetstring.
- Use a 2D DP table to calculate the number of ways to form the
Steps:
- Preprocess
wordsinto a frequency array (counts). - Define a DP function to recursively find the number of ways to form
targetusing the preprocessed counts.
Plan
-
Input Parsing:
- Accept
wordsandtarget.
- Accept
-
Preprocess:
- Create a
countsarray wherecounts[j][char]represents the frequency ofcharat positionjin all words.
- Create a
-
Dynamic Programming:
- Use a recursive function with memoization to compute the number of ways to form
targetusing characters from valid positions inwords.
- Use a recursive function with memoization to compute the number of ways to form
-
Return the Result:
- Return the total count modulo
109 + 7.
- Return the total count modulo
Let's implement this solution in PHP: 1639. Number of Ways to Form a Target String Given a Dictionary
<?php
const MOD = 1000000007;
/**
* @param String[] $words
* @param String $target
* @return Integer
*/
function numWays($words, $target) {
...
...
...
/**
* go to ./solution.php
*/
}
/**
* Helper function for DP
*
* @param $i
* @param $j
* @param $counts
* @param $target
* @param $memo
* @return float|int|mixed
*/
private function dp($i, $j, $counts, $target, &$memo) {
...
...
...
/**
* go to ./solution.php
*/
}
// Example Usage
$words = ["acca", "bbbb", "caca"];
$target = "aba";
echo numWays($words, $target) . "\n"; // Output: 6
$words = ["abba", "baab"];
$target = "bab";
echo numWays($words, $target) . "\n"; // Output: 4
?>
Explanation:
-
Preprocessing Step:
- Build a
countsarray:- For each column in
words, count the occurrences of each character.
- For each column in
- Example: If
words = ["acca", "bbbb", "caca"], for the first column,counts[0] = {'a': 1, 'b': 1, 'c': 1}.
- Build a
-
Recursive DP:
- Define
dp(i, j):-
iis the current index intarget. -
jis the current position inwords.
-
- Base Cases:
- If
i == len(target): Entire target formed → return 1. - If
j == len(words[0]): No more columns to use → return 0.
- If
- Recurrence:
- Option 1: Use
counts[j][target[i]]characters from positionj. - Option 2: Skip position
j.
- Option 1: Use
- Define
-
Optimization:
- Use a memoization table to store results of overlapping subproblems.
Example Walkthrough
Input:
words = ["acca", "bbbb", "caca"], target = "aba"
-
Preprocessing:
counts[0] = {'a': 2, 'b': 0, 'c': 1}counts[1] = {'a': 0, 'b': 3, 'c': 0}counts[2] = {'a': 1, 'b': 0, 'c': 2}counts[3] = {'a': 2, 'b': 0, 'c': 1}
-
DP Calculation:
-
dp(0, 0): How many ways to form"aba"starting from column 0. - Recursively calculate, combining the use of
countsand skipping columns.
-
Output: 6
Time Complexity
-
Preprocessing: O(n x m), where
nis the number of words andmis their length. -
Dynamic Programming: O(l x m), where
lis the length of the target. - Total: O(n x m + l x m).
Output for Example
-
Input:
words = ["acca", "bbbb", "caca"], target = "aba" -
Output:
6
This problem is a great example of combining preprocessing and dynamic programming to solve a combinatorial challenge efficiently.
Contact Links
If you found this series helpful, please consider giving the repository a star on GitHub or sharing the post on your favorite social networks 😍. Your support would mean a lot to me!
If you want more helpful content like this, feel free to follow me:
Top comments (0)