LeetCode 题解工作台
通过给定词典构造目标字符串的方案数
给你一个字符串列表 words 和一个目标字符串 target 。 words 中所有字符串都 长度相同 。 你的目标是使用给定的 words 字符串列表按照下述规则构造 target : 从左到右依次构造 target 的每一个字符。 为了得到 target 第 i 个字符(下标从 0 开始),当…
3
题型
5
代码语言
3
相关题
当前训练重点
困难 · 状态·转移·动态规划
答案摘要
我们注意到,字符串数组 中的每一个字符串长度都相同,不妨记为 ,那么我们可以预处理出一个二维数组 ,其中 表示字符串数组 中第 个位置的字符 的数量。 接下来,我们设计一个函数 $dfs(i, j)$,表示构造 且当前从 中选取的字符位置为 的方案数。那么答案就是 $dfs(0, 0)$。
Interview AiBoxInterview AiBox 实时 AI 助手,陪你讲清 状态·转移·动态规划 题型思路
题目描述
给你一个字符串列表 words 和一个目标字符串 target 。words 中所有字符串都 长度相同 。
你的目标是使用给定的 words 字符串列表按照下述规则构造 target :
- 从左到右依次构造
target的每一个字符。 - 为了得到
target第i个字符(下标从 0 开始),当target[i] = words[j][k]时,你可以使用words列表中第j个字符串的第k个字符。 - 一旦你使用了
words中第j个字符串的第k个字符,你不能再使用words字符串列表中任意单词的第x个字符(x <= k)。也就是说,所有单词下标小于等于k的字符都不能再被使用。 - 请你重复此过程直到得到目标字符串
target。
请注意, 在构造目标字符串的过程中,你可以按照上述规定使用 words 列表中 同一个字符串 的 多个字符 。
请你返回使用 words 构造 target 的方案数。由于答案可能会很大,请对 109 + 7 取余 后返回。
(译者注:此题目求的是有多少个不同的 k 序列,详情请见示例。)
示例 1:
输入:words = ["acca","bbbb","caca"], target = "aba"
输出:6
解释:总共有 6 种方法构造目标串。
"aba" -> 下标为 0 ("acca"),下标为 1 ("bbbb"),下标为 3 ("caca")
"aba" -> 下标为 0 ("acca"),下标为 2 ("bbbb"),下标为 3 ("caca")
"aba" -> 下标为 0 ("acca"),下标为 1 ("bbbb"),下标为 3 ("acca")
"aba" -> 下标为 0 ("acca"),下标为 2 ("bbbb"),下标为 3 ("acca")
"aba" -> 下标为 1 ("caca"),下标为 2 ("bbbb"),下标为 3 ("acca")
"aba" -> 下标为 1 ("caca"),下标为 2 ("bbbb"),下标为 3 ("caca")
示例 2:
输入:words = ["abba","baab"], target = "bab"
输出:4
解释:总共有 4 种不同形成 target 的方法。
"bab" -> 下标为 0 ("baab"),下标为 1 ("baab"),下标为 2 ("abba")
"bab" -> 下标为 0 ("baab"),下标为 1 ("baab"),下标为 3 ("baab")
"bab" -> 下标为 0 ("baab"),下标为 2 ("baab"),下标为 3 ("baab")
"bab" -> 下标为 1 ("abba"),下标为 2 ("baab"),下标为 3 ("baab")
示例 3:
输入:words = ["abcd"], target = "abcd" 输出:1
示例 4:
输入:words = ["abab","baba","abba","baab"], target = "abba" 输出:16
提示:
1 <= words.length <= 10001 <= words[i].length <= 1000words中所有单词长度相同。1 <= target.length <= 1000words[i]和target都仅包含小写英文字母。
解题思路
方法一:预处理 + 记忆化搜索
我们注意到,字符串数组 中的每一个字符串长度都相同,不妨记为 ,那么我们可以预处理出一个二维数组 ,其中 表示字符串数组 中第 个位置的字符 的数量。
接下来,我们设计一个函数 ,表示构造 且当前从 中选取的字符位置为 的方案数。那么答案就是 。
函数 的计算逻辑如下:
- 如果 ,说明 中的所有字符都已经被选取,那么方案数为 。
- 如果 ,说明 中的所有字符都已经被选取,那么方案数为 。
- 否则,我们可以不选择 中的第 个位置的字符,那么方案数为 ;或者我们选择 中的第 个位置的字符,那么方案数为 。
最后,我们返回 即可。注意答案的取模操作。
时间复杂度 ,空间复杂度 。其中 为字符串 的长度,而 为字符串数组 中每个字符串的长度。
class Solution:
def numWays(self, words: List[str], target: str) -> int:
@cache
def dfs(i: int, j: int) -> int:
if i >= m:
return 1
if j >= n:
return 0
ans = dfs(i + 1, j + 1) * cnt[j][ord(target[i]) - ord('a')]
ans = (ans + dfs(i, j + 1)) % mod
return ans
m, n = len(target), len(words[0])
cnt = [[0] * 26 for _ in range(n)]
for w in words:
for j, c in enumerate(w):
cnt[j][ord(c) - ord('a')] += 1
mod = 10**9 + 7
return dfs(0, 0)
复杂度分析
| 指标 | 值 |
|---|---|
| 时间 | complexity is O(wordLength * targetLength + wordLength * totalWords) due to building frequency tables and updating DP states. Space complexity is O(wordLength) to store DP array and temporary frequency counts. |
| 空间 | O(wordLength) |
面试官常问的追问
外企场景- question_mark
Notice if the candidate attempts brute force, highlighting inefficiency in handling large word lists.
- question_mark
Look for correct use of precomputed frequency tables to optimize character lookup at each index.
- question_mark
Confirm that the DP state accurately represents prefix completions of the target string.
常见陷阱
外企场景- error
Forgetting to handle modular arithmetic and producing incorrect large-number outputs.
- error
Confusing word indices and target indices, resulting in invalid character selections.
- error
Overwriting DP states prematurely instead of iterating backwards or using temporary arrays for updates.
进阶变体
外企场景- arrow_right_alt
Limit word lengths to small sizes, focusing on memory-efficient DP optimizations.
- arrow_right_alt
Allow repeated characters in target to test handling of multiple paths using the same words.
- arrow_right_alt
Change constraints to include uppercase letters, requiring adjustments in frequency tables.