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.ith character (0-indexed) of target, you can choose the kth character of the jth string in words if target[i] = words[j][k].kth character of the jth string of words, you can no longer use the xth character of any string in words where x <= k. In other words, all characters to the left of or at index k become unusuable for every 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 <= 1000words have the same length.1 <= target.length <= 1000words[i] and target contain only lowercase English letters.When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:
The brute force approach involves trying every possible combination of characters from the given word list to build the target string. We explore all paths, one character at a time, to see if we can construct the target. We count the number of successful paths.
Here's how the algorithm would work step-by-step:
def number_of_ways_brute_force(
word_list, target_string
):
number_of_ways = 0
def backtrack(
target_index,
current_path,
):
nonlocal number_of_ways
# If we've built the entire target string,
# increment the count
if target_index == len(target_string):
number_of_ways += 1
return
for word in word_list:
# Iterate through each column of the word
for column_index in range(len(word)):
# Check if the character at
# current column matches
if (
column_index < len(word)
and target_string[target_index] == word[column_index]
):
# Explore the next character
backtrack(
target_index + 1,
current_path + [word[column_index]],
)
backtrack(0, [])
return number_of_waysWe want to count how many ways we can build our target string by picking characters from the given dictionary words. The clever trick is to use a system where we remember results we've already calculated, so we don't repeat the same work over and over. This makes the whole process much faster.
Here's how the algorithm would work step-by-step:
def number_of_ways_to_form_target(
dictionary_words, target_string):
word_length = len(dictionary_words[0])
target_length = len(target_string)
modulo = 10**9 + 7
# Stores char frequencies at each index.
character_counts = [([0] * 26) for _ in range(word_length)]
for word in dictionary_words:
for index, char in enumerate(word):
character_counts[index][ord(char) - ord('a')] += 1
memo = {}
def calculate_ways(index_in_target, index_in_word):
if index_in_target == target_length:
return 1
if index_in_word == word_length:
return 0
if (index_in_target, index_in_word) in memo:
return memo[(index_in_target, index_in_word)]
ways = calculate_ways(index_in_target,
index_in_word + 1) % modulo
target_char_index =
ord(target_string[index_in_target]) - ord('a')
#If character can form target.
if character_counts[index_in_word][target_char_index] > 0:
ways += (calculate_ways(index_in_target + 1,
index_in_word + 1) *
character_counts[index_in_word][target_char_index])
ways %= modulo
memo[(index_in_target, index_in_word)] = ways
return ways
# Initiate recursive calls.
result = calculate_ways(0, 0)
return result| Case | How to Handle |
|---|---|
| Empty words array | If the words array is empty, there are zero ways to form the target string; return 0. |
| Empty target string | If the target string is empty, there is one way to form it (by selecting nothing); return 1. |
| Target string longer than the longest word multiplied by number of words | If the target string is longer than the maximum possible length that can be formed, return 0. |
| Words array contains empty strings | Empty strings in words should be ignored or handled as characters that cannot contribute to forming the target. |
| Characters in target string not present in any of the words | If a character in the target string is not present in any of the given words at appropriate indices, the result should be 0. |
| Integer overflow when calculating number of ways | Use modulo operation throughout the calculation to prevent integer overflow (e.g., modulo 10^9 + 7). |
| Words with varying lengths | Handle words of different lengths by ensuring only valid indices are accessed when matching characters. |
| Very large input sizes for words and target that can cause stack overflow during recursion | Use dynamic programming (tabulation) instead of recursion to avoid stack overflow errors. |