Description:
You have 4 cards each containing a number from 1 to 9. You need to judge whether they could operated through *, /, +, -, (, ) to get the value of 24.
Example 1:
Input: [4, 1, 8, 7]
Output: True
Explanation: (8-4) * (7-1) = 24
Example 2:
Input: [1, 2, 1, 2]
Output: False
Note:
1.The division operator / represents real division, not integer division. For example, 4 / (1 - 2/3) = 12.
2.Every operation done is between two numbers. In particular, we cannot use - as a unary operator. For example, with [1, 1, 1, 1] as input, the expression -1 - 1 - 1 - 1 is not allowed.
3.You cannot concatenate numbers together. For example, if the input is [1, 2, 1, 2], we cannot write this as 12 + 12.
问题描述:
输入为一个数组,其中包含4个元素,范围都在[1,9]中,你需要对这四个元素进行四则运算,判断能否得到24.
例子:
输入:[4, 1, 8, 7]
输出:True
解释:(8 - 4) * (7 - 1) = 24
解法1(回溯法):
/*
模拟所有的可能性,一一确认是否可以得到24
*/
class Solution {
public boolean judgePoint24(int[] nums) {
List line = new ArrayList();
for(int i : nums) line.add((double)i);
return solve(line);
}
public boolean solve(List line){
if(line.size() == 0) return false;
if(line.size() == 1) return Math.abs(line.get(0) - 24) < 1e-6;
int size = line.size();
for(int i = 0;i < size;i++){
for(int j = 0;j < size;j++){
if(i == j) continue;
List newLine = new ArrayList();
for(int k = 0;k < size;k++){
if(k != i && k != j) newLine.add(line.get(k));
}
for(int k = 0;k < 4;k++){
//注意这里,因为+号和*号不会因为两个数换个位置就变结果
if(k < 2 && i > j) continue;
double num = 0;
if(k == 0) num = line.get(i) + line.get(j);
if(k == 1) num = line.get(i) * line.get(j);
if(k == 2) num = line.get(i) - line.get(j);
if(k == 3){
//注意这里,/不允许除数为0
if(line.get(j) == 0) continue;
num = line.get(i) / line.get(j);
}
newLine.add(num);
if(solve(newLine)) return true;
newLine.remove(newLine.size() - 1);
}
}
}
return false;
}
}
解法2(回溯法):
class Solution {
final double eps = 0.001;
public boolean judgePoint24(int[] nums) {
return f(new double[] {nums[0], nums[1], nums[2], nums[3]});
}
private boolean f(double[] a) {
if (a.length == 1) {
if(Math.abs(a[0] - 24.0) < eps)
return true;
}
for (int i = 0; i < a.length; i++) {
//注意这里,与解法1不同,因为在compute里面已经包含了两个数的前后顺序
for (int j = i + 1; j < a.length; j++) {
double[] b = new double[a.length - 1];
for (int k = 0, l = 0; k < a.length; k++) {
if (k != i && k != j) {
b[l++] = a[k];
}
}
for (double k : compute(a[i], a[j])) {
b[a.length - 2] = k;
if (f(b)) {
return true;
}
}
}
}
return false;
}
//这里很好,把取数逻辑分离开了
private double[] compute(double a, double b) {
return new double[] {a + b, a - b, b - a, a * b, a / b, b / a};
}
}