问题描述
小M面对一组从 1 到 9 的数字,这些数字被分成多个小组,并从每个小组中选择一个数字组成一个新的数。目标是使得这个新数的各位数字之和为偶数。任务是计算出有多少种不同的分组和选择方法可以达到这一目标。 numbers: 一个由多个整数字符串组成的列表,每个字符串可以视为一个数字组。小M需要从每个数字组中选择一个数字。 例如对于[123, 456, 789],14个符合条件的数为:147 149 158 167 169 248 257 259 268 347 349 358 367 369。 测试样例 样例1: 输入:numbers = [123, 456, 789] 输出:14 样例2: 输入:numbers = [123456789] 输出:4 样例3: 输入:numbers = [14329, 7568] 输出:10
问题理解
首先,我们需要明确问题的具体要求:
- 输入:一个由多个数字字符串组成的列表,例如
[123, 456, 789]
。每个字符串代表一个数字组,小M需要从每个数字组中选择一个数字。 - 目标:组成一个新的数,使得这个数的各位数字之和为偶数。
- 输出:满足条件的不同分组和选择方法的总数。
示例分析
让我们通过提供的样例来更好地理解问题。
样例1:
- 输入:
numbers = [123, 456, 789]
- 输出:
14
样例2:
- 输入:
numbers = [123456789]
- 输出:
4
样例3:
- 输入:
numbers = [14329, 7568]
- 输出:
10
解题思路
为了计算满足条件的选择方法总数,我们可以采用以下步骤:
-
统计每个数字组中奇数和偶数的数量:
- 对于每个数字组,统计其中奇数和偶数的个数。
- 例如,对于数字组
123
,奇数为1
和3
,偶数为2
。
-
动态规划:
- 使用动态规划来记录在选择到第
i
个数字组时,当前数字和的奇偶性。 - 定义
dp[i][j]
,其中i
表示第i
个数字组,j
表示当前数字和的奇偶性(0
表示偶数,1
表示奇数)。 - 初始状态:
dp[0][0] = 1
,表示在选择第0
个数字组之前,数字和为偶数的方案数为1
。
- 使用动态规划来记录在选择到第
-
状态转移:
-
对于每个数字组,更新
dp
表:- 如果选择偶数,则当前数字和的奇偶性不变。
- 如果选择奇数,则当前数字和的奇偶性翻转。
-
具体来说,对于第
i
个数字组,假设其中有even[i]
个偶数和odd[i]
个奇数:dp[i][0] = dp[i-1][0] * even[i] + dp[i-1][1] * odd[i]
dp[i][1] = dp[i-1][1] * even[i] + dp[i-1][0] * odd[i]
-
-
最终结果:
- 最终,
dp[n][0]
即为满足条件的选择方法总数,其中n
是数字组的数量。
- 最终,
具体实现
让我们以样例1为例,具体实现上述思路。
样例1:numbers = [123, 456, 789]
-
统计每个数字组中奇数和偶数的数量:
-
数字组
123
:- 奇数:
1
,3
→ 2 个 - 偶数:
2
→ 1 个
- 奇数:
-
数字组
456
:- 奇数:
5
→ 1 个 - 偶数:
4
,6
→ 2 个
- 奇数:
-
数字组
789
:- 奇数:
7
,9
→ 2 个 - 偶数:
8
→ 1 个
- 奇数:
-
-
初始化
dp
表:dp[0][0] = 1
dp[0][1] = 0
-
状态转移:
-
对于数字组
123
:dp[1][0] = dp[0][0] * 1 + dp[0][1] * 2 = 1 * 1 + 0 * 2 = 1
dp[1][1] = dp[0][1] * 1 + dp[0][0] * 2 = 0 * 1 + 1 * 2 = 2
-
对于数字组
456
:dp[2][0] = dp[1][0] * 2 + dp[1][1] * 1 = 1 * 2 + 2 * 1 = 4
dp[2][1] = dp[1][1] * 2 + dp[1][0] * 1 = 2 * 2 + 1 * 1 = 5
-
对于数字组
789
:dp[3][0] = dp[2][0] * 1 + dp[2][1] * 2 = 4 * 1 + 5 * 2 = 14
dp[3][1] = dp[2][1] * 1 + dp[2][0] * 2 = 5 * 1 + 4 * 2 = 13
-
-
最终结果:
dp[3][0] = 14
,即满足条件的选择方法总数为14
。
代码实现
以下是基于上述思路的 Python 代码实现:
python
复制
def count_even_sum_numbers(numbers):
# 初始化 dp 表
dp = [[0] * 2 for _ in range(len(numbers) + 1)]
dp[0][0] = 1
for i in range(1, len(numbers) + 1):
num_str = numbers[i - 1]
even_count = 0
odd_count = 0
for ch in num_str:
digit = int(ch)
if digit % 2 == 0:
even_count += 1
else:
odd_count += 1
# 更新 dp[i][0] 和 dp[i][1]
dp[i][0] = dp[i - 1][0] * even_count + dp[i - 1][1] * odd_count
dp[i][1] = dp[i - 1][1] * even_count + dp[i - 1][0] * odd_count
return dp[len(numbers)][0]
# 测试样例
print(count_even_sum_numbers(["123", "456", "789"])) # 输出:14
print(count_even_sum_numbers(["123456789"])) # 输出:4
print(count_even_sum_numbers(["14329", "7568"])) # 输出:10
复杂度分析
- 时间复杂度:
O(n * m)
,其中n
是数字组的数量,m
是每个数字组的平均长度。 - 空间复杂度:
O(n)
,用于存储dp
表。