简单解析二分数字组合 | 豆包MarsCode AI刷题

169 阅读3分钟

一、题目分析

首先我们从分析问题开始

分组目标:将数组中的数字分为两组,使得:

  • (1) 一组数字的和的个位数等于A。
  • (2) 另一组数字的和的个位数等于B。
  • (3) 特殊情况,其中一组为空,另一组的和的个位数等于A或B。

根据这个目标要求,将步骤简单概括为以下几点:

  • (1) 遍历数组中的所有可能分组方式。
  • (2) 计算每种分组方式下两组数字的和的个位数。
  • (3) 检查是否满足题目的条件。

举个例子

例如,对于数组 [1, 1, 1] 和目标 A = 1B = 2

  • 分组 1
    • 组1:[1],组2:[1, 1]
    • 组1 的和:1(等于 A)
    • 组2 的和:2(等于 B)
  • 分组 2
    • 组1:[1, 1],组2:[1]
    • 组1 的和:2(等于 B)
    • 组2 的和:1(等于 A)
  • 分组 3
    • 组1:[1],组2:[1,1]
    • 组1 的和:1(等于 A)
    • 组2 的和:2(等于 B)

二、解答题目

由于这道题在题目筛选中位于位运算分类里,所以先尝试用位运算

定义一个函数find(n, A, B, array_a)

  • n:数组 array_a 的长度。
  • A:目标和的一个数。
  • B:目标和的另一个数。
  • array_a:需要进行分组的数组。

计算组合数:使用位运算tc = 1 << n 其中1 << n 相当于 2^n,表示所有可能的组合数(因为每个元素都有两种选择:加入组A或组B)。

接着进入一个循环来遍历所有组合for mask in range(tc)其中mask 是一个从 02^n - 1 的二进制数,每个位上的 01 表示某个元素是加入组A还是组B。

在遍历中加入一个判断条件if mask & (1 << i):判断 mask 的第 i 位是否为 1

  • 若为 1,则将 array_a[i] 加入组A。
  • 否则,将 array_a[i] 加入组B。
for i in range(n): 
    if mask & (1 << i): # 判断第i位是否为1 
        sumA += array_a[i] 
    else: 
        sumB += array_a[i]

检查分组和的个位数if sumA % 10 == A and sumB % 10 == B 若组A和组B的和的个位数分别等于 AB,则计数器 count 增加 1

最后返回结果满足条件的分组方式数量,并对结果取模

这下能轻松秒杀?结果超时了。 尝试询问一下 豆包MarsCode AI 知道了也可以使用动态规划来做这道题,于是尝试换一下方法。

使用动态规划

初始化动态规划表:创建一个三维的动态规划表 dpdp[i][j][k] 表示前 i 个数中,两组数字和的个位数分别为 jk 的组合数。初始状态为 dp[0][0][0] = 1

接着遍历数组元素

  • 遍历数组 array_a
  • 对每个元素 array_a[i-1],考虑将其加入第一组还是第二组,并更新 dp 表。
  • 更新总和 total
for i in range(1, len(array_a) + 1):
    for j in range(10):  # 第一组
        for k in range(10):  # 第二组
            dp[i][j][k] += dp[i-1][((j + 10) - array_a[i-1] % 10) % 10][k]
            dp[i][j][k] += dp[i-1][j][((k + 10) - array_a[i-1] % 10) % 10]
    total += array_a[i-1]

然后处理特殊情况a = 1 if total % 10 == A else 0,另一组也是同理,如果数组的总和total的个位数等于 AB,设置 ab1,表示一组可以为空的情况。

最后返回结果dp[n][A][B] 加上 ab,即满足条件的划分方式数量。轻松解决