将递归解法转换为动态规划:摩尔斯码元音字符串计数优化
嘿,这个问题我熟!你已经摸到了动态规划的门儿——那个S[j]的状态定义方向完全对,咱们把它细化落地,就能得到O(n)时间的解法啦。
优化方案:动态规划(线性时间复杂度)
首先先明确前提:我们需要先把元音对应的摩尔斯码整理好,比如:
- A:
.- - E:
. - I:
.. - O:
--- - U:
..-
1. 完善状态定义
你提到的S[j]可以更精准地定义为:S[j]表示使用前j个摩尔斯字符(也就是原字符串的前j位,索引范围0到j-1)能生成的纯元音字符串的总数量。我们最终要的答案就是S[n],其中n是整个摩尔斯码序列的长度。
2. 初始化基础状态
S[0] = 1:这是一个关键的基础情况——空字符串对应一种“合法的空起点”,当我们匹配到一个元音摩尔斯码时,就可以用这个起点来累加计数。- 其余
S[j](j>0)初始化为0,后续逐步更新。
3. 状态转移逻辑
核心思路是:对于每个位置j,我们检查以j结尾的所有可能的摩尔斯码片段(长度不超过元音摩尔斯码的最大长度),如果某个片段正好是某个元音的摩尔斯码,就把S[i](i是这个片段的起始位置前一位)加到S[j]上。
具体步骤:
- 先把所有元音的摩尔斯码存入一个集合,同时计算这些摩尔斯码的最大长度(比如这里最长的是O的
---,长度为3)。这样我们每次只需要往前最多看3位,不用遍历整个前缀,保证效率。 - 遍历每个
j(从1到n):- 计算起始检查位置
start = max(0, j - max_len),避免越界。 - 从
start到j-1遍历每个i,取出子串morse_str[i:j]。 - 如果这个子串在元音摩尔斯码集合里,就将
S[i]的值加到S[j]上。
- 计算起始检查位置
举个小例子:假设摩尔斯码是".-..",咱们走一遍流程:
S[0] = 1- j=1:子串是
"."(对应E),所以S[1] += S[0]→S[1] = 1 - j=2:子串
".-"(对应A),S[2] += S[0]→S[2] =1;子串"-"不是元音,所以总计数1 - j=3:检查i=1到2:子串
".."(对应I),加S[1]→1;子串"."(对应E),加S[2]→1,所以S[3] = 2 - j=4:检查i=1到3:子串
"-.."不是元音;i=2到4:".."(对应I)加S[2]→1;i=3到4:"."(对应E)加S[3]→2,所以S[4] = 3
最终得到的S[4]就是这段摩尔斯码能生成的纯元音字符串数量。
4. 代码示例(Python)
# 元音与对应摩尔斯码的映射 vowel_morse_map = { 'A': '.-', 'E': '.', 'I': '..', 'O': '---', 'U': '..-' } # 提取摩尔斯码到集合,方便快速查找 morse_codes = set(vowel_morse_map.values()) # 计算最长的摩尔斯码长度,减少后续循环次数 max_code_length = max(len(code) for code in morse_codes) def count_valid_vowel_strings(morse_sequence): n = len(morse_sequence) # 初始化dp数组,dp[j]对应前j个字符的合法数量 dp = [0] * (n + 1) dp[0] = 1 # 空字符串的基础计数 for j in range(1, n + 1): # 确定起始检查位置,避免越界 start_idx = max(0, j - max_code_length) for i in range(start_idx, j): current_substring = morse_sequence[i:j] if current_substring in morse_codes: dp[j] += dp[i] return dp[n]
这个解法的时间复杂度是O(n),因为max_code_length是固定的常数(最多3-4),每个j的内部循环次数是常数级,整体就是线性时间。
内容的提问来源于stack exchange,提问作者Tyler Angelo
相关产品推荐
相关产品推荐

