青训营-二分数字组合

173 阅读3分钟

问题描述

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

例如,对于数组 [1, 1, 1] 和目标 A = 1,B = 2,可行的划分包括三种:每个 1 单独作为一组,其余两个 1 形成另一组。如果 A = 3,B = 5,当所有数字加和的个位数为 3 或 5 时,可以有一组为非空,另一组为空。


测试样例

样例1:

输入:n = 3,A = 1,B = 2,array_a = [1, 1, 1]
输出:3

样例2:

输入:n = 3,A = 3,B = 5,array_a = [1, 1, 1]
输出:1

样例3:

输入:n = 2,A = 1,B = 1,array_a = [1, 1]
输出:2

样例4:

输入:n = 5,A = 3,B = 7,array_a = [2, 3, 5, 7, 9]
输出:0

解题思路

使用动态规划,我们要从“分组和”的角度考虑问题,将数组当中的每个数字分配到两个组中去,并考虑两个组和的个位数,使用动态规划来记录所有的可能,最终得到符合条件的划分方式数。

问题分析

对于给定数组array_a,我们将数组分为两组,要满足:

  • 一组数字的和的个位数等于给定的 A,另一组数字的和的个位数等于给定的 B
    或者
  • 其中一组为空,但剩余数字和的个位数必须等于 A 或 B

动态规划思路

定义一个动态规划状态dp[x][y],x表示当前处理到第几个数,y表示当前组合的个位数
状态更新的依据:
对于每一个数,我们有两种操作:

  • 将其放入第一组,更新第一组和的个位数
  • 将其放入第二组,更新第二组和的个位数

动态规划状态转移

设定dp[i][x][y] 表示考虑前i个数字后,第一组数和的个位数为x且第二组数和的个位数为y的组合数
初始状态dp[0][0][0]=1,表示第0个数字后,第一组数和的个位数为0且第二组数和的个位数为0的组合数为1

状态转移
对于每一个数字num,我们更新

  • 将num放入第一组:dp[i+1][(x+num)%10][y]=dp[i+1][(x+num)%10][y]+dp[i][x][y]
  • 将num放入第二组:dp[i+1][x][(y+num)%10]=dp[i+1][x][(y+num)%10]+dp[i][x][y]

特殊情况

对于一个组合为空,我们将所有数字加和进行比较即可

代码实现

public class Main {
    public static int solution(int n, int A, int B, int[] array_a) {
        // Please write your code here
        int result ;
        int sum = 0;
        
        // 计算数组元素的和
        for (int i = 0; i < array_a.length; i++) {
            sum += array_a[i];
        }
        
        // 如果所有数的和的个位数是A或者B
        if ((sum % 10) == A || (sum % 10) == B) {
            result = 1;
        } else {
            result = 0;
        }
        
        // 使用三维数组 dp 来记录分配情况
        int[][][] dp = new int[n + 1][10][10];
        dp[0][0][0] = 1;  // 初始化:没有数字时,和为0的情况
 // 动态规划处理数组
 for (int i = 0; i < n; i++) {
    int num = array_a[i];
    for (int x = 0; x < 10; x++) {
        for (int y = 0; y < 10; y++) {
            if (dp[i][x][y] > 0) {
                // 将当前数放入第一组
                dp[i+1 ][(x + num) % 10][y] += dp[i][x][y];
                // 将当前数放入第二组
                dp[i+1 ][x][(y + num) % 10] += dp[i][x][y];
               
            }
        }
    }
}
// 统计满足条件的划分方法
result += dp[n][A][B];



return result;
    }

    public static void main(String[] args) {
        //  You can add more test cases here
        int[] array1 = {1, 1, 1};
        int[] array2 = {1, 1, 1};
        int[] array3 = {1, 1};
        int[] array4 = {2,3,5,7,9};
        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);
        System.out.println(solution(5, 3, 7, array4) == 0);
    }
}