问题描述
小S定义了一个字符串的权值,规则是:相邻的不同字符对的数量。例如,对于字符串 "10011"
,其权值为2,因为其中有2对相邻字符是不同的。现在小S拿到一个只包含 '0'
、 '1'
和 '?'
的字符串,其中 '?'
表示这个位置可以是 '0'
或 '1'
。已知共有2k2k种可能的字符串(kk 是问号的数量)。小S希望知道,这2k2k种可能的字符串的权值之和是多少?注意答案需要对109+7109+7取模。
例如,对于字符串 "01?"
,可能的串是 "010"
和 "011"
,它们的权值分别为2和1,权值和为3。
测试样例
样例1:
输入:
s = "01?"
输出:3
样例2:
输入:
s = "1??0"
输出:6
样例3:
输入:
s = "?"
输出:0
问题分析
- 定义权值:字符串的权值定义为相邻不同字符对的数量,例如字符串
"10011"
中,有2对相邻字符是不同的。 - 未知字符:字符串中可能包含字符
?
,每个?
可以是0
或1
。因此,含有k
个?
的字符串有 种可能的替换。 - 目标:计算所有可能的字符串的权值之和,并对结果取模 。
解题思路
-
动态规划:我们可以通过递归或动态规划的方式来计算所有可能的字符串及其权值。
-
状态转移:对于每一个
?
字符,我们可以将其替换为0
或1
,分别计算替换后的权值,然后累加所有可能的组合。 -
记忆化:为了避免重复计算,可以使用记忆化存储每个子问题的结果。
-
边界情况:
- 如果字符串中没有
?
,直接计算权值。 - 如果字符串长度为1,权值总是0,因为没有相邻字符。
- 如果字符串中没有
示例解答
我们可以用递归 + 记忆化的方法实现。
MOD = 10**9 + 7
def calculate_weight(s):
# 计算字符串的权值
weight = 0
for i in range(1, len(s)):
if s[i] != s[i - 1]:
weight += 1
return weight
def dfs(s, index, memo):
# DFS 搜索所有可能的字符串
if index == len(s):
# 如果到达字符串末尾,计算权值
return calculate_weight(s)
# 使用记忆化来存储已计算的状态
if (s, index) in memo:
return memo[(s, index)]
if s[index] == '?':
# 如果当前位置是问号,分别替换为 '0' 和 '1' 并计算总和
sum_weight = 0
for char in '01':
new_s = s[:index] + char + s[index+1:]
sum_weight += dfs(new_s, index + 1, memo)
sum_weight %= MOD
memo[(s, index)] = sum_weight
return sum_weight
else:
# 如果当前位置不是问号,继续向下递归
result = dfs(s, index + 1, memo)
memo[(s, index)] = result
return result
def solution(s: str) -> int:
memo = {}
return dfs(s, 0, memo)
# 测试用例
if __name__ == '__main__':
print(solution("01?") == 3) # True
print(solution("1??0") == 6) # True
print(solution("?") == 0) # True
解释代码
calculate_weight
: 用于计算没有?
的字符串的权值。dfs
: 使用递归和记忆化来遍历字符串的所有可能组合。如果遇到?
,分别替换成0
和1
,并递归计算权值之和。solution
: 主函数,初始化记忆化字典memo
,并调用dfs
进行计算。