前言
本文以“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回答:“
思路提示
-
理解问题核心:
- 你需要将数组分成两组,使得一组的和的个位数等于 A,另一组的和的个位数等于 B。
- 还有一种特殊情况允许其中一组为空,但剩余数字和的个位数必须等于 A 或 B。
-
数据结构选择:
- 由于你需要对数组进行划分,考虑使用动态规划(DP)或回溯法来尝试所有可能的划分。
- 你可以使用一个布尔数组来记录哪些数字被选中,哪些没有被选中。 ”
思路分析
有了AI的提示,我们可以考虑使用动态规划来解决这道题。
记数组为,并且可以定义来表示的前个字符,分成的两组数字之和个位数分别为和的情况,这里我们规定,对于的情况不做定义,即不推导也不使用。
初始状态,,其他都默认为。
状态转移方程: 首先我们定义,用来分别表示从两个不同的分组可以转移到当前的状态中。那么:
其中的和函数仅仅只是用来保证访问的第二个下标应当大于等于第一个下标。
这样一来便可以得到最终的,此外,需要注意的是题意中的特殊情况不可以加或者是,因为这其中的0表示的是某一分组的数字和个位数是0,而不是该分组为空,所以特殊情况特殊处理即可。
最后,我们可以进行一些空间优化,观察到状态转移方程实际上与第三维无关,我们可以用滚动数组优化掉这一维占用的空间,那么空间复杂度为,另外可以分析计算时间复杂度为。
代码
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);
}