刷题实践选题 & 题解32 二分数字组合 | 豆包MarsCode AI刷题

85 阅读4分钟

前言

本文以“32. 二分数字组合”为例,阐述一下AI刷题的功能亮点。

题意简述

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

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

AI助力思路分析

帮助理解题意

很多时候,可能由于题意表述不清楚,并且样例数量过少,导致我们没有理解清楚题意。在AI的帮助下,我们可以让AI在不泄露题目解析的情况下,重述题意,并且帮我们多生成几组样例,便于我们理解清楚题意。

例如这道题,我们问AI:“我没有理解清楚题意,请帮我多生成几组正确的样例输入输出。” AI回答:“好的,我可以帮助你理解题意并提供更多的样例输入输出。

题目描述回顾

你需要将一个数组中的数字分为两组,使得一组数字的和的个位数等于给定的 A,另一组数字的和的个位数等于给定的 B。还有一种特殊情况允许其中一组为空,但剩余数字和的个位数必须等于 A 或 B。你需要计算所有可能的划分方式。

更多样例

样例5:

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

  • 一组为 [1, 2],另一组为 [3, 4],和的个位数分别为 3 和 7,不符合条件。
  • 一组为 [1, 3],另一组为 [2, 4],和的个位数分别为 4 和 6,不符合条件。
  • 一组为 [1, 4],另一组为 [2, 3],和的个位数分别为 5 和 5,不符合条件。
  • 一组为 [1],另一组为 [2, 3, 4],和的个位数分别为 1 和 9,不符合条件。
  • 一组为 [2],另一组为 [1, 3, 4],和的个位数分别为 2 和 8,符合条件。
  • 一组为 [3],另一组为 [1, 2, 4],和的个位数分别为 3 和 7,符合条件。
  • 一组为 [4],另一组为 [1, 2, 3],和的个位数分别为 4 和 6,不符合条件。
    因此,只有两种划分方式符合条件。

思路提示

如果我们需要一点思路提示,也可以问AI,并让AI尽量不要给出详细的解答,而是给我们提示引导我们自己想出正确的方法。

例如本题,我们可以询问AI:“我需要一点思路提示,但是不要过于详细,请引导我自己想出题目的正确思路。”

AI回答:“

思路提示

  1. 理解问题核心

    • 你需要将数组分成两组,使得一组的和的个位数等于 A,另一组的和的个位数等于 B。
    • 还有一种特殊情况允许其中一组为空,但剩余数字和的个位数必须等于 A 或 B。
  2. 数据结构选择

    • 由于你需要对数组进行划分,考虑使用动态规划(DP)或回溯法来尝试所有可能的划分。
    • 你可以使用一个布尔数组来记录哪些数字被选中,哪些没有被选中。 ”

思路分析

有了AI的提示,我们可以考虑使用动态规划来解决这道题。

记数组为aa,并且可以定义dp[i][j][k]dp[i][j][k]来表示aa的前kk个字符,分成的两组数字之和个位数分别为iijj的情况,这里我们规定iji\leq j,对于iji\geq j的情况不做定义,即不推导也不使用。

初始状态,dp[0][0][0]=1dp[0][0][0]=1,其他都默认为00

状态转移方程: 首先我们定义i_1=(ia[k]%10+10)%10,j_1=(ja[k]%10+10)%10i\_1=(i-a[k]\%10+10)\%10,j\_1=(j-a[k]\%10+10)\%10,用来分别表示从两个不同的分组可以转移到当前的状态中。那么:

dp[i][j][k]=dp[min{i_1,j}][max{i_1,j}][k1]+dp[min{i,j_1}][max{i,j_1}][k1],ij\begin{align} dp[i][j][k]= &dp[\min\{i\_1, j\}][\max\{i\_1, j\}][k-1]\\ & +dp[\min\{i, j\_1\}][\max\{i, j\_1\}][k-1], i\leq j \end{align}

其中的min\minmax\max函数仅仅只是用来保证访问dpdp的第二个下标应当大于等于第一个下标。

这样一来便可以得到最终的dp[A][B][n],ABdp[A][B][n], A\leq B,此外,需要注意的是题意中的特殊情况不可以加dp[0][A][n]dp[0][A][n]或者是dp[0][B][n]dp[0][B][n],因为这其中的0表示的是某一分组的数字和个位数是0,而不是该分组为空,所以特殊情况特殊处理即可。

最后,我们可以进行一些空间优化,观察到状态转移方程实际上与第三维无关,我们可以用滚动数组优化掉这一维占用的空间,那么空间复杂度为O(1)O(1),另外可以分析计算时间复杂度为O(n)O(n)

代码

using namespace std;
int solution(int n, int A, int B, std::vector<int> array_a) {
    // Please write your code here
    vector<vector<vector<int>>> dp(10, 
                                vector<vector<int>>(10, 
                                    vector<int>(2, 0)));
    array_a.insert(array_a.begin(), 0);
    dp[0][0][0] = 1;
    int tmp = 0;
    for (int k = 1; k <= n; k++) {
        tmp = (tmp + array_a[k] % 10) % 10;
        for (int i = 0; i < 10; i++) {
            for (int j = i; j < 10; j++) {
            	int tmpi_1, tmpj_1;
            	tmpi_1 = (i - array_a[k] % 10 + 10) % 10;
            	tmpj_1 = (j - array_a[k] % 10 + 10) % 10;
                dp[i][j][k&1] = dp[min(tmpi_1, j)][max(tmpi_1, j)][(k^1)&1] + 
                			  dp[min(i, tmpj_1)][max(i, tmpj_1)][(k^1)&1];
            }
        }
    }
    return dp[min(A, B)][max(A, B)][n&1] + (tmp == A ? 1 : tmp == B);
}