- 「这是我参与2022首次更文挑战的第5天,活动详情查看:2022首次更文挑战」
1、题目描述
你有 4 张写有 1 到 9 数字的牌。你需要判断是否能通过 *,/,+,-,(,) 的运算得到 24。注意事项如下。
- 除法运算符 / 表示实数除法,而不是整数除法。例如 4 / (1 - 2/3) = 12 。
- 每个运算符对两个数进行运算。特别是我们不能用 - 作为一元运算符。例如,[1, 1, 1, 1] 作为输入时,表达式 -1 - 1 - 1 - 1 是不允许的。
- 你不能将数字连接在一起。例如,输入为 [1, 2, 1, 2] 时,不能写成 12 + 12 。 示例 1:
输入: [4, 1, 8, 7]
输出: True
解释: (8-4) * (7-1) = 24
2、思路
卡牌的数量只有四张,所以我们可以将卡牌进行全排列,一共有 4 * 3 * 2 * 1 = 24 种排列组合情况。而后再用递归的方法进行一个运算符运算,以此合并两个数成一个数,缩小数据个数(要考虑所有的两个不等价数的运算情况)。最后缩小成一个数时,进行判断即可,我们使用的是小数代替分数,因此在最后的结果会有很小的误差,所以在接近 24 的值就是可以组合了。
3、代码及注解
public boolean judgePoint24(int[] c) {
double[] cards = new double[4];
for (int i = 0; i < 4; i++) {
cards[i] = c[i];
}
for (int i = 0; i < 4; i++) { // 对卡牌进行全排列
for (int j = 0; j < 4; j++) {
if (i == j) continue;
for (int m = 0; m < 4; m++) {
if (i == m || j == m) continue;
for (int n = 0; n < 4; n++) {
if (i == n || j == n || m == n) continue;
if (check_4(cards[i],cards[j],cards[m],cards[n])) return true;
}
}
}
}
return false;
}
// 缩小一个运算符,因为 d1 和 d2 和 d3 和 d4 是等价的,所以考虑前两个就可以了。
private boolean check_4(double d1, double d2, double d3, double d4) {
return check_3(d1 + d2,d3,d4) ||
check_3(d1 - d2,d3,d4) ||
check_3(d1 * d2,d3,d4) ||
check_3(d1 / d2,d3,d4);
}
// 缩小一个运算符,d2 和 d3 是等价的,d1 与 d2 不等价,d1 与 d3 不等价,要对 d1 与 d2、d1 与 d3 进行交换递归。
private boolean check_3(double d1, double d2, double d3) {
return check_2(d1 + d2,d3) ||
check_2(d1 - d2,d3) ||
check_2(d1 * d2,d3) ||
check_2(d1 / d2,d3) ||
check_2(d2 - d1,d3) ||
check_2(d2 / d1,d3) ||
check_2(d1,d2 + d3) ||
check_2(d1,d2 - d3) ||
check_2(d1,d2 * d3) ||
check_2(d1,d2 / d3);
}
// 此时 d1 与 d2 全都不等价,所以要考虑d1 d2 的全部组合运算情况。
private boolean check_2(double d1, double d2) {
return check(d1 + d2) ||
check(d1 - d2) ||
check(d1 * d2) ||
check(d1 / d2) ||
check(d2 - d1) ||
check(d2 / d1);
}
// 由于我们用切确值表示分数,所以最后计算结果接近估计值就可以了。
private boolean check(double d) {
return d > 23.9 && d < 24.1;
}