题目描述
你有 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:
输入: [1, 2, 1, 2]
输出: False
解法
1. 回溯
思路:这道题拿到手里我是一点想法都没有😑(太菜了),直接看的官方题解。[其实这里也类似于DFS😮]
可以通过回溯的方法来遍历所有的不同可能性。具体做法是,使用一个列表储存所有数字,每次从列表中选出两个索引不同的数字,再选择一种运算操作,得到的数用来代替之前选的两个数,列表中的数字就减少1个。重复过程一直到列表只剩下一个数字,这个数字就是一种可能性结果。如果等于24,则可以通过运算得到24;如果所有可能结果都不等于24,则无法通过运算得到24。
注意
- 除法运算为实数运算,不是整数除法,需要先转换为double类型。此时判断是否等于24需要考虑到精度,这里误差小于$10^{-6}$即可认为相等。
- 加法和乘法都具有交换律,所以如果是这两种运算,可以不考虑选择元素的顺序,减小运算量。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
| import java.util.ArrayList; import java.util.List; class Solution { static final int TARGET = 24; static final double EPSILON = 1e-6; static final int ADD = 0, MULTIPLY = 1, SUBSTRACT = 2, DIVIDED = 3;
public boolean judgePoint24(int[] nums) { if (nums == null || nums.length == 0) return false; List<Double> list = new ArrayList<>(); for (int i = 0; i < nums.length; i++) { list.add((double) nums[i]); } return solve(list); }
private boolean solve(List<Double> list) { if (list.size() == 1) return Math.abs(list.get(0) - TARGET) < EPSILON; for (int i = 0; i < list.size(); i++) { for (int j = 0; j < list.size(); j++) { if (i != j) { List<Double> list2 = new ArrayList<>(); for (int k = 0; k < list.size(); k++) { if (k != i && k != j) list2.add(list.get(k)); } for (int method = 0; method < 4; method++) { if (method < 2 && i > j) continue; if (method == ADD) { list2.add(list.get(i) + list.get(j)); } else if (method == MULTIPLY) { list2.add(list.get(i) * list.get(j)); } else if (method == SUBSTRACT) { list2.add(list.get(i) - list.get(j)); } else if (method == DIVIDED) { if (Math.abs(list.get(j)) < EPSILON) continue; list2.add(list.get(i) / list.get(j)); } if (solve(list2)) return true; list2.remove(list2.size() - 1); } } } } return false; } }
|
时间复杂度为$O(1)$ 因为牌只有四张,其排列组合的个数是确定的,规模不会改变,每个排列执行的代码次数也是常数的。
空间复杂度为$O(1)$ 递归栈空间大小为牌的张数4
参考