今天看到有人问了这个二分数字组合,正好解答一下。
题目链接:二分数字组合 - MarsCode
先分析题目:
小F面临一个有趣的挑战:给定一个数组,她需要将数组中的数字分为两组。
分组的目标是使得一组数字的和的个位数等于给定的 A,另一组数字的和的个位数等于给定的 B。
除此之外,还有一种特殊情况允许其中一组为空,但剩余数字和的个位数必须等于 A 或 B。
小F需要计算所有可能的划分方式。
例如,对于数组 [1, 1, 1] 和目标 A = 1,B = 2
可行的划分包括三种:每个 1 单独作为一组,其余两个 1 形成另一组。
如果 A = 3,B = 5,当所有数字加和的个位数为 3 或 5 时,可以有一组为非空,另一组为空。
通过题目我们可以得知,我们可以将一个数组拆分成两个,并且两个数组和的个位数等于题目要求 其中,拆分的两个数组一个可以为空。
我们将题目可以分成两个要求
1.两个数组满足两个目标
2.一个数组为空,其余和的个位数为目标之一
我们先考虑第二个要求
在这里第二个要求的解决方案是,先将题目数组对10求余数
这一步先保证数组里保存的是个位数,这便于之后的运算
接下来我们使用sum函数将数组个位数求一下和,并二次对10求余
然后我们可以得出,是否满足于条件2
同时,因为条件2只需要数组的全部,只有一种特殊情况
判断完成后返回就可以了
array_a = [x % 10 for x in array_a]
total_sum = sum(array_a)
total_sum %= 10
if (total_sum == A or total_sum == B):
return 1
if (total_sum != (A + B) % 10):
return 0
然后我们看第一个要求,将数组拆分,而且相同的数字也算+1的结果
首先想到动态规划
f = [[0 for _ in range(10)] for _ in range(n + 1)]
初始一个二维数组
包含 `n+1` 行和 `10` 列,并且所有元素都被初始化为 `0`
然后我们遍历数组,从1开始直到n
这一步是遍历每一个元素
然后我们继续遍历,从0到9
这一步是确认个位数的和
for i in range(1, n + 1):
for j in range(10):
# 当前元素不放入当前和的方案数,等于前一个元素的方案数
f[i][j] += f[i - 1][j]
# 当前元素放入当前和的方案数,等于前一个元素减去当前元素个位数后的方案数
f[i][j] += f[i - 1][(j - array_a[i - 1] + 10) % 10]
上述两步我们动态进行一个状态的改变
表示在考虑前 `i` 个元素时,和的个位数为 `j` 的方案数,等于不考虑第 `i` 个元素时,和的个位数为 `j` 的方案数。
这是因为如果不选择第 `i` 个元素,那么前 `i-1` 个元素的和的个位数仍然是 `j`,所以方案数不变。
表示在考虑前 `i` 个元素时,和的个位数为 `j` 的方案数,等于不考虑第 `i` 个元素时,和的个位数为 `j - array_a[i - 1]` 的方案数。
这是因为如果选择第 `i` 个元素,那么前 `i-1` 个元素的和的个位数需要减去第 `i` 个元素的个位数,即 `array_a[i - 1]`,才能得到当前和的个位数 `j`。
由于个位数的范围是 `0` 到 `9`,所以需要对结果进行模 `10` 运算,以确保结果在正确的范围内。
最后,我们返回二维数组的[n][B]