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

108 阅读4分钟

题目

小F面临一个有趣的挑战:给定一个数组,她需要将数组中的数字分为两组。分组的目标是使得一组数字的和的个位数等于给定的 A,另一组数字的和的个位数等于给定的 B。除此之外,还有一种特殊情况允许其中一组为空,但剩余数字和的个位数必须等于 A 或 B。小F需要计算所有可能的划分方式。

例如,对于数组 [1, 1, 1] 和目标 A = 1,B = 2,可行的划分包括三种:每个 1 单独作为一组,其余两个 1 形成另一组。如果 A = 3,B = 5,当所有数字加和的个位数为 3 或 5 时,可以有一组为非空,另一组为空。 理解题目是解决问题的第一步。让我们深入分析题目要求,确保我们对问题的理解是准确的。

题目理解

问题描述: 小F面临一个挑战:给定一个数组,她需要将数组中的数字分为两组。分组的目标是使得一组数字的和的个位数等于给定的 A,另一组数字的和的个位数等于给定的 B。除此之外,还有一种特殊情况允许其中一组为空,但剩余数字和的个位数必须等于 A 或 B。小F需要计算所有可能的划分方式。

关键点:

  1. 分组目标:

    • 一组数字的和的个位数等于 A
    • 另一组数字的和的个位数等于 B
  2. 特殊情况:

    • 允许其中一组为空,但剩余数字和的个位数必须等于 A 或 B
  3. 计算所有可能的划分方式:

    • 需要计算所有满足上述条件的划分方式的数量。

示例:

  • 示例1:

    • 输入:n = 3, A = 1, B = 2, array_a = [1, 1, 1]
    • 输出:3
    • 解释:可行的划分包括三种:每个 1 单独作为一组,其余两个 1 形成另一组。
  • 示例2:

    • 输入:n = 3, A = 3, B = 5, array_a = [1, 1, 1]
    • 输出:1
    • 解释:所有数字加和的个位数为 3,可以有一组为非空,另一组为空。

解题思路

  1. 动态规划(DP) :

    • 使用动态规划来记录每一步的状态。
    • dp[i][j][k] 表示前 i 个数字,第一组的和的个位数为 j,第二组的和的个位数为 k 时的划分方案数。
  2. 状态转移:

    • 对于每个数字,可以选择将其加入第一组或第二组。
    • 更新 dp[i][j][k] 时,考虑当前数字加入第一组或第二组的情况。
  3. 特殊情况处理:

    • 如果所有数字的总和的个位数等于 A 或 B,则可以有一组为空。

代码

public class Main {
    public static int solution(int n, int A, int B, int[] array_a) {
        // dp: dp[i][j][k] 表示前i个数字,个位数分别为j和k时的划分方案数
        int[][][] dp = new int[n+1][10][10];
        //初始化dp数组
        dp[0][0][0] = 1;
        int sum = 0;
        // 第i个数
        for(int i = 1;i <= array_a.length;i++){
            //第一组
            for(int j = 0;j < 10; j++){
                //第二组
                for(int k = 0;k < 10; k++){
                    //加入第一组
                    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];
                }
            }
            //累加
            sum += array_a[i-1];
        }
        //总和个位数是否为A
        int a = sum % 10 == A ? 1:0;
        //总和个位数是否为B
        int b = sum % 10 == B ? 1:0;
        int result = dp[n][A][B] + a + b;
        return result;
    }

    public static void main(String[] args) {
        int[] array1 = {1, 1, 1};
        int[] array2 = {1, 1, 1};
        int[] array3 = {1, 1};

        System.out.println(solution(3, 1, 2, array1) == 3);
        System.out.println(solution(3, 3, 5, array2) == 1);
        System.out.println(solution(2, 1, 1, array3) == 2);
    }
}

代码解释

  1. 动态规划数组 dp:

    • dp[i][j][k] 表示前 i 个数字,第一组的和的个位数为 j,第二组的和的个位数为 k 时的划分方案数。
    • dp[0][0][0] = 1 表示前0个数字时,个位数分别为0和0的划分方案数为1。
  2. 遍历数组:

    • 对于每个数字 array_a[i-1],遍历所有可能的个位数组合 (j, k)

    • 更新 dp[i][j][k]

      • 将当前数字加入第一组: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]
  3. 累加总和:

    • 计算所有数字的总和 sum
  4. 判断总和的个位数:

    • 如果总和的个位数等于 A,则 a = 1,否则 a = 0
    • 如果总和的个位数等于 B,则 b = 1,否则 b = 0
  5. 计算结果:

    • 结果为 dp[n][A][B] + a + b,即所有数字的总和个位数为 A 或 B 的情况。
  6. 测试样例:

    • 在 main 方法中,通过测试样例验证代码的正确性。