问题背景
在编程和算法领域,我们经常会遇到一些看似简单但实际上需要巧妙解决方案的问题。今天,我们要探讨的就是这样一个问题:给定一个由数字字符和问号(?)组成的字符串,我们的任务是将所有的问号替换成数字字符,使得替换后的字符串表示的十进制整数成为给定正整数p的倍数。这个问题不仅考验了我们对字符串操作的熟练程度,还涉及到了动态规划和模运算的知识。
问题描述
小C拿到了一个由数字字符和问号(?)组成的字符串,她的目标是将所有的问号替换成数字字符,使得替换后的字符串表示的十进制整数成为正整数p的倍数。由于方案数可能非常大,需要对最终的结果取模 109+7109+7。
代码实现
为了解决这个问题,我们可以使用动态规划的方法。以下是Python语言的实现代码:
def solution(s: str, p: int) -> int:
MOD = 10**9 + 7
n = len(s)
dp = [[0] * p for _ in range(n + 1)]
# 初始化
dp[0][0] = 1
# 遍历字符串
for i in range(n):
for r in range(p):
if dp[i][r] > 0:
if s[i] == '?':
for digit in range(10):
new_r = (r * 10 + digit) % p
dp[i + 1][new_r] = (dp[i + 1][new_r] + dp[i][r]) % MOD
else:
digit = int(s[i])
new_r = (r * 10 + digit) % p
dp[i + 1][new_r] = (dp[i + 1][new_r] + dp[i][r]) % MOD# 最终答案
return dp[n][0]
if __name__ == '__main__':
print(solution("??", 1) == 100)
print(solution("????1", 12) == 0)
print(solution("1??2", 3) == 34)
代码分析
初始化
我们首先定义了一个模数 MOD,这是为了处理大数问题。然后,我们初始化了一个二维数组 dp,其中 dp[i][j] 表示字符串的前 i 个字符能被 j 整除的方案数。
动态规划逻辑
我们使用两层循环来遍历字符串和可能的余数。对于每个字符,如果它是问号,我们尝试用0到9的数字替换它,并更新 dp 数组。如果字符不是问号,我们直接使用它,并更新 dp 数组。
更新 dp 数组
在更新 dp 数组时,我们使用了取模操作来确保结果不会超出整数范围。
最终结果
最后,我们返回 dp[n][0],它表示整个字符串能被 p 整除的方案数。
难点分析
- 动态规划状态转移:理解如何根据当前状态更新下一个状态是解决这个问题的关键。
- 大数处理:由于结果可能非常大,我们需要在每一步都进行取模操作以避免整数溢出。
- 边界条件处理:在处理字符串的最后一个字符时,我们需要确保它能够正确地影响最终的结果。