二分数字组合| 豆包MarsCode AI 刷题

55 阅读4分钟

问题分析

假设我们有一个数组 nums 和目标值 AB,目标是将数组中的元素分为两组,使得:

  • 第一组的和的个位数是 A
  • 第二组的和的个位数是 B
  • 或者其中一组为空,另一组的和的个位数等于 A 或 B

这里有几个要点需要注意:

  1. 每组的和只关心个位数,因此我们只需要处理数字的个位数。
  2. 如果一组为空,那么剩下的数字的和的个位数必须等于 A 或 B
  3. 我们需要枚举所有可能的分组方式来检查是否满足要求。

解题思路

  1. 对个位数进行运算:我们关注的是数组元素的个位数,因为最终目标是计算和的个位数。

  2. 使用动态规划或背包问题思想

    • 我们可以考虑动态规划的方式,维护一个状态表示可能的和的个位数。
    • 可以设定一个状态 dp[i][j],表示从前 i 个元素中选出若干个元素,使得这些元素的和的个位数为 j
    • 每次处理一个数字时,我们需要更新状态,考虑当前数字是否被选择以及选择后的和的个位数。
  3. 考虑特殊情况:对于一个组为空的情况,我们可以简单地判断所有数字和的个位数是否为 AB

动态规划状态设计

  • 设定一个状态 dp[j],表示当前是否能得到和的个位数是 j
  • 初始时,dp[0] = 1,表示和为 0 是可行的(即空集合的和)。
  • 然后,对于每个数字 num,更新状态 dp。对于每个现有的和的个位数 j,考虑是否加上当前数字 num,即更新 dp[(j + num) % 10]

动态规划更新过程

  1. 初始化

    • dp[0] = 1(表示和为 0 是可行的,初始时空集和的和为 0)。
  2. 状态更新

    • 遍历数组中的每个元素 num
    • 对于每个已有的 dp[j](表示已有的和的个位数),计算 (j + num) % 10 来更新状态。
    • 这样我们通过状态转移确保可以得到所有可能的和的个位数。
  3. 检查是否可以满足 A 或 B

    • 我们需要分别检查最终是否能得到和的个位数为 A 或 B,或者一组为空,剩余数字的和的个位数为 A 或 B

代码实现

pythonCopy Code
def countWays(nums, A, B):
    # 先计算所有数字的个位数
    nums = [num % 10 for num in nums]
    
    # dp[i] 表示是否可以获得和为 i 的个位数
    dp = [0] * 10
    dp[0] = 1  # 初始状态,和为 0 是可行的(即空集)

    # 动态规划更新
    for num in nums:
        # 这里我们从后往前更新dp,防止重复计算
        new_dp = dp[:]
        for j in range(10):
            new_dp[(j + num) % 10] += dp[j]
        dp = new_dp
    
    # 最后dp[A] 和 dp[B] 分别代表能否通过分配得到和为A或B的分法
    # 还要考虑一个特殊情况:有一组为空,剩下的和为A或B
    total_sum = sum(nums) % 10
    result = dp[A] + dp[B]
    
    # 如果 total_sum % 10 == A 或 B,则可以通过一组为空的情况满足
    if total_sum == A or total_sum == B:
        result += 1
    
    return result

# 示例
nums = [1, 1, 1]
A = 1
B = 2
print(countWays(nums, A, B))  # 输出可能的分组方式数

代码解析

  1. 初始化

    • 将数组 nums 中的每个数字取个位数,以减少计算复杂度。
    • 初始化 dp[0] = 1,表示和为 0 是可能的。
  2. 动态规划

    • 对于每个数字 num,从已有的 dp 状态中计算新状态。这里使用 new_dp 来存储更新后的结果,避免在同一轮中更新 dp 造成的覆盖问题。
  3. 特殊情况

    • 如果整个数组的和的个位数已经是 A 或 B,那么可以考虑将一组设置为空,剩下的数字就满足要求。
  4. 输出

    • 返回所有满足条件的分组方式的总数。

时间复杂度

  • 时间复杂度:O(n * 10),其中 n 是数组的长度,10 是因为我们只关心和的个位数(0到9)。
  • 空间复杂度:O(10),因为我们只需要一个大小为 10 的数组来存储状态。

总结

通过动态规划的方式,我们能够在 O(n) 时间内计算所有可能的分组方式。核心思想是将问题转化为求和的个位数,利用状态转移来记录所有可能的情况,从而满足题目要求。