二分数字组合 题解 | 豆包MarsCode AI刷题
题目链接:二分数字组合
官方定级:易
相关技巧:动态规划
问题描述
小F面临一个有趣的挑战:给定一个数组,她需要将数组中的数字分为两组。分组的目标是使得一组数字的和的个位数等于给定的 A,另一组数字的和的个位数等于给定的 B。除此之外,还有一种特殊情况允许其中一组为空,但剩余数字和的个位数必须等于 A 或 B。小F需要计算所有可能的划分方式。
例如,对于数组 [1, 1, 1] 和目标 A = 1,B = 2,可行的划分包括三种:每个 1 单独作为一组,其余两个 1 形成另一组。如果 A = 3,B = 5,当所有数字加和的个位数为 3 或 5 时,可以有一组为非空,另一组为空。
思路
首先,题目要求将数组中的数字分为两组,其中一组数字和的个位数为A,另一组数字和的个位数为B。看起来需要满足两个条件,但实际上,对于同样的输入数组,只要确定了其中一组数字和的个位数,那么另外一组数字和的个位数就是固定的。即:假定第一组数字和的个位数为M,第二组数字和的个位数为N,而所有数字和的个位数为S,则一定有(M+N)%10 == S,在M和S固定的情况下N是唯一的。
假设所有数字之和的个位数为 S,此题可分为以下两种情况:
- (1) (A + B) % 10 == S,则只需求解:从所有数中取出一部分,使得其和的个位数为A的方法数量(此时剩余数字和的个位数一定为B)。此分类中,一组为空的情况会一并被计算,无需单独考虑;
- (2) (A + B) % 10 != S,则不存在任何分法可使得一组和的个位数为A,另一组和的个位数为B。此时只需关注题目所述的特殊情况(即一组为空的情况)。
另外,注意到本题只需关注和的个位数,因此求和时只存储结果的个位数即可。
dp过程
此题可选择采用动态规划求解。动态规划子问题为:从数组的前x个数中取任意数量的数,使得它们的和的个位数为i(0<=i<=9)的方案数量。
递推:
设前x个数中取任意数组合使得和的个位数为i的方案数量为dp[x][i] (0 <= i <= 9)
则 dp[x+1][i] = dp[x][i] + dp[x][(i-arr[x+1])%10]
解释:前x+1个数中取任意数组合使得和的个位数为i的方案可分为两种。第一种为不取第x+1个数,此类方案数量等同于在前x个数中取任意数组合,使得和的个位数为i的方案数量;第二种为取第x+1个数,此类方案数量等同于在前x个数中取出某些数,使得其个位数P满足 (P+arr[x+1])%10 == i 的方案数量。
例如:已知在前100个数中取任意数量的数,使得其和的个位数为3的方案数量为 dp[100][3] = 114,使得其和的个位数为7的方案数量为 dp[100][7] = 810。第101个数为514,现求在前101个数中取任意数量的数,使得其个位数为7的方案数量(即求dp[101][7])。
第一种,不取第101个数,则等同于在前100个数中取数,一共有dp[100][7] = 810种,
第二种,取第101个数(514),那么如果想使得取出数的和个位数为7,则前100个数中取的数和的个位数必须为3,这样3 + 514 = 517的个位数才能是7。这样的方案有dp[100][3] = 114种。
故 dp[101][7] = dp[100][7] + dp[100][3] = 810 + 114 = 924
注:以上开二维数组仅为解释方便,实际上本题无需存储之前的所有数据,只需存储最近一轮的结果即可。
代码实现
def solution(n, A, B, arr):
d = { k: 0 for k in range(10) }
d[0] = 1 # 不取任何数时和为0
for i in arr: # 遍历数组中每个数
d = { k: d[k] + d[(k-i)%10] for k in range(10)}
s = sum(arr)
if (s - A - B) % 10 == 0: # 情况(1)
return d[A]
else: # 情况(2)
return (s % 10 == A % 10) + (s % 10 == B % 10)
复杂度分析
时间复杂度
dp过程遍历数组中每个元素一次,每个元素进行10次循环,消常后复杂度为
求和亦遍历每个元素一次,复杂度为
总时间复杂度即为
空间复杂度
除初始数组外,无论输入大小,都只需存储固定数量的变量,故空间复杂度为