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:
-
target
should be formed from left to right. - To form the
ith
character (0-indexed) oftarget
, you can choose thekth
character of thejth
string in words iftarget[i] = words[j][k]
. - Once you use the
kth
character of thejth
string ofwords
, you can no longer use thexth
character of any string inwords
wherex <= k
. In other words, all characters to the left of or at indexk
become 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 <= 1000
1 <= words[i].length <= 1000
- All strings in
words
have the same length. 1 <= target.length <= 1000
-
words[i]
andtarget
contain only lowercase English letters.
Hint:
- For each index i, store the frequency of each character in the
ith
row. - 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
target
due 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
target
string.
- Use a 2D DP table to calculate the number of ways to form the
Steps:
- Preprocess
words
into a frequency array (counts
). - Define a DP function to recursively find the number of ways to form
target
using the preprocessed counts.
Plan
-
Input Parsing:
- Accept
words
andtarget
.
- Accept
-
Preprocess:
- Create a
counts
array wherecounts[j][char]
represents the frequency ofchar
at positionj
in all words.
- Create a
-
Dynamic Programming:
- Use a recursive function with memoization to compute the number of ways to form
target
using 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
counts
array:- 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)
:-
i
is the current index intarget
. -
j
is 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
counts
and skipping columns.
-
Output: 6
Time Complexity
-
Preprocessing: O(n x m), where
n
is the number of words andm
is their length. -
Dynamic Programming: O(l x m), where
l
is 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)